blob: ee0ceda72ea3c1437276ba656b26e77803f34f6b [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,
Bram Moolenaar29500652021-08-08 15:43:34 +020032 float_T *value, // result stored here
33 int skip_quotes)
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +020034{
35 char *s = (char *)text;
36 float_T f;
37
38 // MS-Windows does not deal with "inf" and "nan" properly.
39 if (STRNICMP(text, "inf", 3) == 0)
40 {
41 *value = INFINITY;
42 return 3;
43 }
44 if (STRNICMP(text, "-inf", 3) == 0)
45 {
46 *value = -INFINITY;
47 return 4;
48 }
49 if (STRNICMP(text, "nan", 3) == 0)
50 {
51 *value = NAN;
52 return 3;
53 }
Bram Moolenaar29500652021-08-08 15:43:34 +020054 if (skip_quotes && vim_strchr((char_u *)s, '\'') != NULL)
55 {
56 char_u buf[100];
57 char_u *p = buf;
58 int quotes = 0;
59
60 vim_strncpy(buf, (char_u *)s, 99);
61 p = buf;
62 for (;;)
63 {
64 // remove single quotes between digits, not in the exponent
65 if (*p == '\'')
66 {
67 ++quotes;
68 mch_memmove(p, p + 1, STRLEN(p));
69 }
70 if (!vim_isdigit(*p))
71 break;
72 p = skipdigits(p);
73 }
74 s = (char *)buf;
75 f = strtod(s, &s);
76 *value = f;
77 return (int)((char_u *)s - buf) + quotes;
78 }
79
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +020080 f = strtod(s, &s);
81 *value = f;
82 return (int)((char_u *)s - text);
83}
84
85/*
86 * Get the float value of "argvars[0]" into "f".
87 * Returns FAIL when the argument is not a Number or Float.
88 */
89 static int
90get_float_arg(typval_T *argvars, float_T *f)
91{
92 if (argvars[0].v_type == VAR_FLOAT)
93 {
94 *f = argvars[0].vval.v_float;
95 return OK;
96 }
97 if (argvars[0].v_type == VAR_NUMBER)
98 {
99 *f = (float_T)argvars[0].vval.v_number;
100 return OK;
101 }
102 emsg(_("E808: Number or Float required"));
103 return FAIL;
104}
105
106/*
107 * "abs(expr)" function
108 */
109 void
110f_abs(typval_T *argvars, typval_T *rettv)
111{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200112 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
113 return;
114
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200115 if (argvars[0].v_type == VAR_FLOAT)
116 {
117 rettv->v_type = VAR_FLOAT;
118 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
119 }
120 else
121 {
122 varnumber_T n;
123 int error = FALSE;
124
125 n = tv_get_number_chk(&argvars[0], &error);
126 if (error)
127 rettv->vval.v_number = -1;
128 else if (n > 0)
129 rettv->vval.v_number = n;
130 else
131 rettv->vval.v_number = -n;
132 }
133}
134
135/*
136 * "acos()" function
137 */
138 void
139f_acos(typval_T *argvars, typval_T *rettv)
140{
141 float_T f = 0.0;
142
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200143 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
144 return;
145
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200146 rettv->v_type = VAR_FLOAT;
147 if (get_float_arg(argvars, &f) == OK)
148 rettv->vval.v_float = acos(f);
149 else
150 rettv->vval.v_float = 0.0;
151}
152
153/*
154 * "asin()" function
155 */
156 void
157f_asin(typval_T *argvars, typval_T *rettv)
158{
159 float_T f = 0.0;
160
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200161 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
162 return;
163
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200164 rettv->v_type = VAR_FLOAT;
165 if (get_float_arg(argvars, &f) == OK)
166 rettv->vval.v_float = asin(f);
167 else
168 rettv->vval.v_float = 0.0;
169}
170
171/*
172 * "atan()" function
173 */
174 void
175f_atan(typval_T *argvars, typval_T *rettv)
176{
177 float_T f = 0.0;
178
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200179 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
180 return;
181
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200182 rettv->v_type = VAR_FLOAT;
183 if (get_float_arg(argvars, &f) == OK)
184 rettv->vval.v_float = atan(f);
185 else
186 rettv->vval.v_float = 0.0;
187}
188
189/*
190 * "atan2()" function
191 */
192 void
193f_atan2(typval_T *argvars, typval_T *rettv)
194{
195 float_T fx = 0.0, fy = 0.0;
196
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200197 if (in_vim9script()
198 && (check_for_float_or_nr_arg(argvars, 0) == FAIL
199 || check_for_float_or_nr_arg(argvars, 1) == FAIL))
200 return;
201
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200202 rettv->v_type = VAR_FLOAT;
203 if (get_float_arg(argvars, &fx) == OK
204 && get_float_arg(&argvars[1], &fy) == OK)
205 rettv->vval.v_float = atan2(fx, fy);
206 else
207 rettv->vval.v_float = 0.0;
208}
209
210/*
211 * "ceil({float})" function
212 */
213 void
214f_ceil(typval_T *argvars, typval_T *rettv)
215{
216 float_T f = 0.0;
217
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200218 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
219 return;
220
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200221 rettv->v_type = VAR_FLOAT;
222 if (get_float_arg(argvars, &f) == OK)
223 rettv->vval.v_float = ceil(f);
224 else
225 rettv->vval.v_float = 0.0;
226}
227
228/*
229 * "cos()" function
230 */
231 void
232f_cos(typval_T *argvars, typval_T *rettv)
233{
234 float_T f = 0.0;
235
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200236 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
237 return;
238
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200239 rettv->v_type = VAR_FLOAT;
240 if (get_float_arg(argvars, &f) == OK)
241 rettv->vval.v_float = cos(f);
242 else
243 rettv->vval.v_float = 0.0;
244}
245
246/*
247 * "cosh()" function
248 */
249 void
250f_cosh(typval_T *argvars, typval_T *rettv)
251{
252 float_T f = 0.0;
253
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200254 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
255 return;
256
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200257 rettv->v_type = VAR_FLOAT;
258 if (get_float_arg(argvars, &f) == OK)
259 rettv->vval.v_float = cosh(f);
260 else
261 rettv->vval.v_float = 0.0;
262}
263
264/*
265 * "exp()" function
266 */
267 void
268f_exp(typval_T *argvars, typval_T *rettv)
269{
270 float_T f = 0.0;
271
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200272 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
273 return;
274
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200275 rettv->v_type = VAR_FLOAT;
276 if (get_float_arg(argvars, &f) == OK)
277 rettv->vval.v_float = exp(f);
278 else
279 rettv->vval.v_float = 0.0;
280}
281
282/*
283 * "float2nr({float})" function
284 */
285 void
286f_float2nr(typval_T *argvars, typval_T *rettv)
287{
288 float_T f = 0.0;
289
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200290 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
291 return;
292
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200293 if (get_float_arg(argvars, &f) == OK)
294 {
295 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
296 rettv->vval.v_number = -VARNUM_MAX;
297 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
298 rettv->vval.v_number = VARNUM_MAX;
299 else
300 rettv->vval.v_number = (varnumber_T)f;
301 }
302}
303
304/*
305 * "floor({float})" function
306 */
307 void
308f_floor(typval_T *argvars, typval_T *rettv)
309{
310 float_T f = 0.0;
311
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200312 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
313 return;
314
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200315 rettv->v_type = VAR_FLOAT;
316 if (get_float_arg(argvars, &f) == OK)
317 rettv->vval.v_float = floor(f);
318 else
319 rettv->vval.v_float = 0.0;
320}
321
322/*
323 * "fmod()" function
324 */
325 void
326f_fmod(typval_T *argvars, typval_T *rettv)
327{
328 float_T fx = 0.0, fy = 0.0;
329
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200330 if (in_vim9script()
331 && (check_for_float_or_nr_arg(argvars, 0) == FAIL
332 || check_for_float_or_nr_arg(argvars, 1) == FAIL))
333 return;
334
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200335 rettv->v_type = VAR_FLOAT;
336 if (get_float_arg(argvars, &fx) == OK
337 && get_float_arg(&argvars[1], &fy) == OK)
338 rettv->vval.v_float = fmod(fx, fy);
339 else
340 rettv->vval.v_float = 0.0;
341}
342
343# if defined(HAVE_MATH_H) || defined(PROTO)
344/*
345 * "isinf()" function
346 */
347 void
348f_isinf(typval_T *argvars, typval_T *rettv)
349{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200350 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
351 return;
352
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200353 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
354 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
355}
356
357/*
358 * "isnan()" function
359 */
360 void
361f_isnan(typval_T *argvars, typval_T *rettv)
362{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200363 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
364 return;
365
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200366 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
367 && isnan(argvars[0].vval.v_float);
368}
369# endif
370
371/*
372 * "log()" function
373 */
374 void
375f_log(typval_T *argvars, typval_T *rettv)
376{
377 float_T f = 0.0;
378
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200379 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
380 return;
381
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200382 rettv->v_type = VAR_FLOAT;
383 if (get_float_arg(argvars, &f) == OK)
384 rettv->vval.v_float = log(f);
385 else
386 rettv->vval.v_float = 0.0;
387}
388
389/*
390 * "log10()" function
391 */
392 void
393f_log10(typval_T *argvars, typval_T *rettv)
394{
395 float_T f = 0.0;
396
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200397 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
398 return;
399
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200400 rettv->v_type = VAR_FLOAT;
401 if (get_float_arg(argvars, &f) == OK)
402 rettv->vval.v_float = log10(f);
403 else
404 rettv->vval.v_float = 0.0;
405}
406
407/*
408 * "pow()" function
409 */
410 void
411f_pow(typval_T *argvars, typval_T *rettv)
412{
413 float_T fx = 0.0, fy = 0.0;
414
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200415 if (in_vim9script()
416 && (check_for_float_or_nr_arg(argvars, 0) == FAIL
417 || check_for_float_or_nr_arg(argvars, 1) == FAIL))
418 return;
419
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200420 rettv->v_type = VAR_FLOAT;
421 if (get_float_arg(argvars, &fx) == OK
422 && get_float_arg(&argvars[1], &fy) == OK)
423 rettv->vval.v_float = pow(fx, fy);
424 else
425 rettv->vval.v_float = 0.0;
426}
427
428
429/*
430 * round() is not in C90, use ceil() or floor() instead.
431 */
432 float_T
433vim_round(float_T f)
434{
435 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
436}
437
438/*
439 * "round({float})" function
440 */
441 void
442f_round(typval_T *argvars, typval_T *rettv)
443{
444 float_T f = 0.0;
445
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200446 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
447 return;
448
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200449 rettv->v_type = VAR_FLOAT;
450 if (get_float_arg(argvars, &f) == OK)
451 rettv->vval.v_float = vim_round(f);
452 else
453 rettv->vval.v_float = 0.0;
454}
455
456/*
457 * "sin()" function
458 */
459 void
460f_sin(typval_T *argvars, typval_T *rettv)
461{
462 float_T f = 0.0;
463
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200464 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
465 return;
466
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200467 rettv->v_type = VAR_FLOAT;
468 if (get_float_arg(argvars, &f) == OK)
469 rettv->vval.v_float = sin(f);
470 else
471 rettv->vval.v_float = 0.0;
472}
473
474/*
475 * "sinh()" function
476 */
477 void
478f_sinh(typval_T *argvars, typval_T *rettv)
479{
480 float_T f = 0.0;
481
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200482 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
483 return;
484
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200485 rettv->v_type = VAR_FLOAT;
486 if (get_float_arg(argvars, &f) == OK)
487 rettv->vval.v_float = sinh(f);
488 else
489 rettv->vval.v_float = 0.0;
490}
491
492/*
493 * "sqrt()" function
494 */
495 void
496f_sqrt(typval_T *argvars, typval_T *rettv)
497{
498 float_T f = 0.0;
499
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200500 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
501 return;
502
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200503 rettv->v_type = VAR_FLOAT;
504 if (get_float_arg(argvars, &f) == OK)
505 rettv->vval.v_float = sqrt(f);
506 else
507 rettv->vval.v_float = 0.0;
508}
509
510/*
511 * "str2float()" function
512 */
513 void
514f_str2float(typval_T *argvars, typval_T *rettv)
515{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200516 char_u *p;
517 int isneg;
Bram Moolenaar29500652021-08-08 15:43:34 +0200518 int skip_quotes;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200519
520 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
521 return;
522
Bram Moolenaar29500652021-08-08 15:43:34 +0200523 skip_quotes = argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]);
524
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200525 p = skipwhite(tv_get_string_strict(&argvars[0]));
526 isneg = (*p == '-');
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200527
528 if (*p == '+' || *p == '-')
529 p = skipwhite(p + 1);
Bram Moolenaar29500652021-08-08 15:43:34 +0200530 (void)string2float(p, &rettv->vval.v_float, skip_quotes);
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200531 if (isneg)
532 rettv->vval.v_float *= -1;
533 rettv->v_type = VAR_FLOAT;
534}
535
536/*
537 * "tan()" function
538 */
539 void
540f_tan(typval_T *argvars, typval_T *rettv)
541{
542 float_T f = 0.0;
543
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200544 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
545 return;
546
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200547 rettv->v_type = VAR_FLOAT;
548 if (get_float_arg(argvars, &f) == OK)
549 rettv->vval.v_float = tan(f);
550 else
551 rettv->vval.v_float = 0.0;
552}
553
554/*
555 * "tanh()" function
556 */
557 void
558f_tanh(typval_T *argvars, typval_T *rettv)
559{
560 float_T f = 0.0;
561
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200562 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
563 return;
564
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200565 rettv->v_type = VAR_FLOAT;
566 if (get_float_arg(argvars, &f) == OK)
567 rettv->vval.v_float = tanh(f);
568 else
569 rettv->vval.v_float = 0.0;
570}
571
572/*
573 * "trunc({float})" function
574 */
575 void
576f_trunc(typval_T *argvars, typval_T *rettv)
577{
578 float_T f = 0.0;
579
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200580 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
581 return;
582
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200583 rettv->v_type = VAR_FLOAT;
584 if (get_float_arg(argvars, &f) == OK)
585 // trunc() is not in C90, use floor() or ceil() instead.
586 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
587 else
588 rettv->vval.v_float = 0.0;
589}
590
591#endif