blob: 1361a36d50ef66d0a4f1c7edd388fe003e780867 [file] [log] [blame]
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * float.c: Floating point functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if (defined(FEAT_EVAL) && defined(FEAT_FLOAT)) || defined(PROTO)
18
19#ifdef VMS
20# include <float.h>
21#endif
22
23/*
24 * Convert the string "text" to a floating point number.
25 * This uses strtod(). setlocale(LC_NUMERIC, "C") has been used to make sure
26 * this always uses a decimal point.
27 * Returns the length of the text that was consumed.
28 */
29 int
30string2float(
31 char_u *text,
32 float_T *value) // result stored here
33{
34 char *s = (char *)text;
35 float_T f;
36
37 // MS-Windows does not deal with "inf" and "nan" properly.
38 if (STRNICMP(text, "inf", 3) == 0)
39 {
40 *value = INFINITY;
41 return 3;
42 }
43 if (STRNICMP(text, "-inf", 3) == 0)
44 {
45 *value = -INFINITY;
46 return 4;
47 }
48 if (STRNICMP(text, "nan", 3) == 0)
49 {
50 *value = NAN;
51 return 3;
52 }
53 f = strtod(s, &s);
54 *value = f;
55 return (int)((char_u *)s - text);
56}
57
58/*
59 * Get the float value of "argvars[0]" into "f".
60 * Returns FAIL when the argument is not a Number or Float.
61 */
62 static int
63get_float_arg(typval_T *argvars, float_T *f)
64{
65 if (argvars[0].v_type == VAR_FLOAT)
66 {
67 *f = argvars[0].vval.v_float;
68 return OK;
69 }
70 if (argvars[0].v_type == VAR_NUMBER)
71 {
72 *f = (float_T)argvars[0].vval.v_number;
73 return OK;
74 }
75 emsg(_("E808: Number or Float required"));
76 return FAIL;
77}
78
79/*
80 * "abs(expr)" function
81 */
82 void
83f_abs(typval_T *argvars, typval_T *rettv)
84{
85 if (argvars[0].v_type == VAR_FLOAT)
86 {
87 rettv->v_type = VAR_FLOAT;
88 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
89 }
90 else
91 {
92 varnumber_T n;
93 int error = FALSE;
94
95 n = tv_get_number_chk(&argvars[0], &error);
96 if (error)
97 rettv->vval.v_number = -1;
98 else if (n > 0)
99 rettv->vval.v_number = n;
100 else
101 rettv->vval.v_number = -n;
102 }
103}
104
105/*
106 * "acos()" function
107 */
108 void
109f_acos(typval_T *argvars, typval_T *rettv)
110{
111 float_T f = 0.0;
112
113 rettv->v_type = VAR_FLOAT;
114 if (get_float_arg(argvars, &f) == OK)
115 rettv->vval.v_float = acos(f);
116 else
117 rettv->vval.v_float = 0.0;
118}
119
120/*
121 * "asin()" function
122 */
123 void
124f_asin(typval_T *argvars, typval_T *rettv)
125{
126 float_T f = 0.0;
127
128 rettv->v_type = VAR_FLOAT;
129 if (get_float_arg(argvars, &f) == OK)
130 rettv->vval.v_float = asin(f);
131 else
132 rettv->vval.v_float = 0.0;
133}
134
135/*
136 * "atan()" function
137 */
138 void
139f_atan(typval_T *argvars, typval_T *rettv)
140{
141 float_T f = 0.0;
142
143 rettv->v_type = VAR_FLOAT;
144 if (get_float_arg(argvars, &f) == OK)
145 rettv->vval.v_float = atan(f);
146 else
147 rettv->vval.v_float = 0.0;
148}
149
150/*
151 * "atan2()" function
152 */
153 void
154f_atan2(typval_T *argvars, typval_T *rettv)
155{
156 float_T fx = 0.0, fy = 0.0;
157
158 rettv->v_type = VAR_FLOAT;
159 if (get_float_arg(argvars, &fx) == OK
160 && get_float_arg(&argvars[1], &fy) == OK)
161 rettv->vval.v_float = atan2(fx, fy);
162 else
163 rettv->vval.v_float = 0.0;
164}
165
166/*
167 * "ceil({float})" function
168 */
169 void
170f_ceil(typval_T *argvars, typval_T *rettv)
171{
172 float_T f = 0.0;
173
174 rettv->v_type = VAR_FLOAT;
175 if (get_float_arg(argvars, &f) == OK)
176 rettv->vval.v_float = ceil(f);
177 else
178 rettv->vval.v_float = 0.0;
179}
180
181/*
182 * "cos()" function
183 */
184 void
185f_cos(typval_T *argvars, typval_T *rettv)
186{
187 float_T f = 0.0;
188
189 rettv->v_type = VAR_FLOAT;
190 if (get_float_arg(argvars, &f) == OK)
191 rettv->vval.v_float = cos(f);
192 else
193 rettv->vval.v_float = 0.0;
194}
195
196/*
197 * "cosh()" function
198 */
199 void
200f_cosh(typval_T *argvars, typval_T *rettv)
201{
202 float_T f = 0.0;
203
204 rettv->v_type = VAR_FLOAT;
205 if (get_float_arg(argvars, &f) == OK)
206 rettv->vval.v_float = cosh(f);
207 else
208 rettv->vval.v_float = 0.0;
209}
210
211/*
212 * "exp()" function
213 */
214 void
215f_exp(typval_T *argvars, typval_T *rettv)
216{
217 float_T f = 0.0;
218
219 rettv->v_type = VAR_FLOAT;
220 if (get_float_arg(argvars, &f) == OK)
221 rettv->vval.v_float = exp(f);
222 else
223 rettv->vval.v_float = 0.0;
224}
225
226/*
227 * "float2nr({float})" function
228 */
229 void
230f_float2nr(typval_T *argvars, typval_T *rettv)
231{
232 float_T f = 0.0;
233
234 if (get_float_arg(argvars, &f) == OK)
235 {
236 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
237 rettv->vval.v_number = -VARNUM_MAX;
238 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
239 rettv->vval.v_number = VARNUM_MAX;
240 else
241 rettv->vval.v_number = (varnumber_T)f;
242 }
243}
244
245/*
246 * "floor({float})" function
247 */
248 void
249f_floor(typval_T *argvars, typval_T *rettv)
250{
251 float_T f = 0.0;
252
253 rettv->v_type = VAR_FLOAT;
254 if (get_float_arg(argvars, &f) == OK)
255 rettv->vval.v_float = floor(f);
256 else
257 rettv->vval.v_float = 0.0;
258}
259
260/*
261 * "fmod()" function
262 */
263 void
264f_fmod(typval_T *argvars, typval_T *rettv)
265{
266 float_T fx = 0.0, fy = 0.0;
267
268 rettv->v_type = VAR_FLOAT;
269 if (get_float_arg(argvars, &fx) == OK
270 && get_float_arg(&argvars[1], &fy) == OK)
271 rettv->vval.v_float = fmod(fx, fy);
272 else
273 rettv->vval.v_float = 0.0;
274}
275
276# if defined(HAVE_MATH_H) || defined(PROTO)
277/*
278 * "isinf()" function
279 */
280 void
281f_isinf(typval_T *argvars, typval_T *rettv)
282{
283 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
284 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
285}
286
287/*
288 * "isnan()" function
289 */
290 void
291f_isnan(typval_T *argvars, typval_T *rettv)
292{
293 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
294 && isnan(argvars[0].vval.v_float);
295}
296# endif
297
298/*
299 * "log()" function
300 */
301 void
302f_log(typval_T *argvars, typval_T *rettv)
303{
304 float_T f = 0.0;
305
306 rettv->v_type = VAR_FLOAT;
307 if (get_float_arg(argvars, &f) == OK)
308 rettv->vval.v_float = log(f);
309 else
310 rettv->vval.v_float = 0.0;
311}
312
313/*
314 * "log10()" function
315 */
316 void
317f_log10(typval_T *argvars, typval_T *rettv)
318{
319 float_T f = 0.0;
320
321 rettv->v_type = VAR_FLOAT;
322 if (get_float_arg(argvars, &f) == OK)
323 rettv->vval.v_float = log10(f);
324 else
325 rettv->vval.v_float = 0.0;
326}
327
328/*
329 * "pow()" function
330 */
331 void
332f_pow(typval_T *argvars, typval_T *rettv)
333{
334 float_T fx = 0.0, fy = 0.0;
335
336 rettv->v_type = VAR_FLOAT;
337 if (get_float_arg(argvars, &fx) == OK
338 && get_float_arg(&argvars[1], &fy) == OK)
339 rettv->vval.v_float = pow(fx, fy);
340 else
341 rettv->vval.v_float = 0.0;
342}
343
344
345/*
346 * round() is not in C90, use ceil() or floor() instead.
347 */
348 float_T
349vim_round(float_T f)
350{
351 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
352}
353
354/*
355 * "round({float})" function
356 */
357 void
358f_round(typval_T *argvars, typval_T *rettv)
359{
360 float_T f = 0.0;
361
362 rettv->v_type = VAR_FLOAT;
363 if (get_float_arg(argvars, &f) == OK)
364 rettv->vval.v_float = vim_round(f);
365 else
366 rettv->vval.v_float = 0.0;
367}
368
369/*
370 * "sin()" function
371 */
372 void
373f_sin(typval_T *argvars, typval_T *rettv)
374{
375 float_T f = 0.0;
376
377 rettv->v_type = VAR_FLOAT;
378 if (get_float_arg(argvars, &f) == OK)
379 rettv->vval.v_float = sin(f);
380 else
381 rettv->vval.v_float = 0.0;
382}
383
384/*
385 * "sinh()" function
386 */
387 void
388f_sinh(typval_T *argvars, typval_T *rettv)
389{
390 float_T f = 0.0;
391
392 rettv->v_type = VAR_FLOAT;
393 if (get_float_arg(argvars, &f) == OK)
394 rettv->vval.v_float = sinh(f);
395 else
396 rettv->vval.v_float = 0.0;
397}
398
399/*
400 * "sqrt()" function
401 */
402 void
403f_sqrt(typval_T *argvars, typval_T *rettv)
404{
405 float_T f = 0.0;
406
407 rettv->v_type = VAR_FLOAT;
408 if (get_float_arg(argvars, &f) == OK)
409 rettv->vval.v_float = sqrt(f);
410 else
411 rettv->vval.v_float = 0.0;
412}
413
414/*
415 * "str2float()" function
416 */
417 void
418f_str2float(typval_T *argvars, typval_T *rettv)
419{
420 char_u *p = skipwhite(tv_get_string(&argvars[0]));
421 int isneg = (*p == '-');
422
423 if (*p == '+' || *p == '-')
424 p = skipwhite(p + 1);
425 (void)string2float(p, &rettv->vval.v_float);
426 if (isneg)
427 rettv->vval.v_float *= -1;
428 rettv->v_type = VAR_FLOAT;
429}
430
431/*
432 * "tan()" function
433 */
434 void
435f_tan(typval_T *argvars, typval_T *rettv)
436{
437 float_T f = 0.0;
438
439 rettv->v_type = VAR_FLOAT;
440 if (get_float_arg(argvars, &f) == OK)
441 rettv->vval.v_float = tan(f);
442 else
443 rettv->vval.v_float = 0.0;
444}
445
446/*
447 * "tanh()" function
448 */
449 void
450f_tanh(typval_T *argvars, typval_T *rettv)
451{
452 float_T f = 0.0;
453
454 rettv->v_type = VAR_FLOAT;
455 if (get_float_arg(argvars, &f) == OK)
456 rettv->vval.v_float = tanh(f);
457 else
458 rettv->vval.v_float = 0.0;
459}
460
461/*
462 * "trunc({float})" function
463 */
464 void
465f_trunc(typval_T *argvars, typval_T *rettv)
466{
467 float_T f = 0.0;
468
469 rettv->v_type = VAR_FLOAT;
470 if (get_float_arg(argvars, &f) == OK)
471 // trunc() is not in C90, use floor() or ceil() instead.
472 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
473 else
474 rettv->vval.v_float = 0.0;
475}
476
477#endif