blob: 4c8e5fe10ad9cc21980ae58816bc9b8a2791a3df [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
Bram Moolenaar73e28dc2022-09-17 21:08:33 +010017#if defined(FEAT_EVAL) || defined(PROTO)
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +020018
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 }
John Marriott10f69292025-04-14 21:19:34 +020044 if (STRNICMP(text, "-inf", 4) == 0)
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +020045 {
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];
Yegappan Lakshmananc99e1822022-09-03 10:52:24 +010057 char_u *p;
Bram Moolenaar29500652021-08-08 15:43:34 +020058 int quotes = 0;
59
60 vim_strncpy(buf, (char_u *)s, 99);
Yegappan Lakshmananc99e1822022-09-03 10:52:24 +010061 for (p = buf; ; p = skipdigits(p))
Bram Moolenaar29500652021-08-08 15:43:34 +020062 {
63 // remove single quotes between digits, not in the exponent
64 if (*p == '\'')
65 {
66 ++quotes;
67 mch_memmove(p, p + 1, STRLEN(p));
68 }
69 if (!vim_isdigit(*p))
70 break;
Bram Moolenaar29500652021-08-08 15:43:34 +020071 }
72 s = (char *)buf;
73 f = strtod(s, &s);
74 *value = f;
75 return (int)((char_u *)s - buf) + quotes;
76 }
77
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +020078 f = strtod(s, &s);
79 *value = f;
80 return (int)((char_u *)s - text);
81}
82
83/*
84 * Get the float value of "argvars[0]" into "f".
85 * Returns FAIL when the argument is not a Number or Float.
86 */
87 static int
88get_float_arg(typval_T *argvars, float_T *f)
89{
90 if (argvars[0].v_type == VAR_FLOAT)
91 {
92 *f = argvars[0].vval.v_float;
93 return OK;
94 }
95 if (argvars[0].v_type == VAR_NUMBER)
96 {
97 *f = (float_T)argvars[0].vval.v_number;
98 return OK;
99 }
Bram Moolenaar9d00e4a2022-01-05 17:49:15 +0000100 emsg(_(e_number_or_float_required));
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200101 return FAIL;
102}
103
104/*
105 * "abs(expr)" function
106 */
107 void
108f_abs(typval_T *argvars, typval_T *rettv)
109{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200110 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
111 return;
112
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200113 if (argvars[0].v_type == VAR_FLOAT)
114 {
115 rettv->v_type = VAR_FLOAT;
116 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
117 }
118 else
119 {
120 varnumber_T n;
121 int error = FALSE;
122
123 n = tv_get_number_chk(&argvars[0], &error);
124 if (error)
125 rettv->vval.v_number = -1;
126 else if (n > 0)
127 rettv->vval.v_number = n;
128 else
129 rettv->vval.v_number = -n;
130 }
131}
132
133/*
134 * "acos()" function
135 */
136 void
137f_acos(typval_T *argvars, typval_T *rettv)
138{
139 float_T f = 0.0;
140
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200141 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
142 return;
143
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200144 rettv->v_type = VAR_FLOAT;
145 if (get_float_arg(argvars, &f) == OK)
146 rettv->vval.v_float = acos(f);
147 else
148 rettv->vval.v_float = 0.0;
149}
150
151/*
152 * "asin()" function
153 */
154 void
155f_asin(typval_T *argvars, typval_T *rettv)
156{
157 float_T f = 0.0;
158
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200159 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
160 return;
161
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200162 rettv->v_type = VAR_FLOAT;
163 if (get_float_arg(argvars, &f) == OK)
164 rettv->vval.v_float = asin(f);
165 else
166 rettv->vval.v_float = 0.0;
167}
168
169/*
170 * "atan()" function
171 */
172 void
173f_atan(typval_T *argvars, typval_T *rettv)
174{
175 float_T f = 0.0;
176
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200177 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
178 return;
179
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200180 rettv->v_type = VAR_FLOAT;
181 if (get_float_arg(argvars, &f) == OK)
182 rettv->vval.v_float = atan(f);
183 else
184 rettv->vval.v_float = 0.0;
185}
186
187/*
188 * "atan2()" function
189 */
190 void
191f_atan2(typval_T *argvars, typval_T *rettv)
192{
193 float_T fx = 0.0, fy = 0.0;
194
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200195 if (in_vim9script()
196 && (check_for_float_or_nr_arg(argvars, 0) == FAIL
197 || check_for_float_or_nr_arg(argvars, 1) == FAIL))
198 return;
199
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200200 rettv->v_type = VAR_FLOAT;
201 if (get_float_arg(argvars, &fx) == OK
202 && get_float_arg(&argvars[1], &fy) == OK)
203 rettv->vval.v_float = atan2(fx, fy);
204 else
205 rettv->vval.v_float = 0.0;
206}
207
208/*
209 * "ceil({float})" function
210 */
211 void
212f_ceil(typval_T *argvars, typval_T *rettv)
213{
214 float_T f = 0.0;
215
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200216 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
217 return;
218
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200219 rettv->v_type = VAR_FLOAT;
220 if (get_float_arg(argvars, &f) == OK)
221 rettv->vval.v_float = ceil(f);
222 else
223 rettv->vval.v_float = 0.0;
224}
225
226/*
227 * "cos()" function
228 */
229 void
230f_cos(typval_T *argvars, typval_T *rettv)
231{
232 float_T f = 0.0;
233
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200234 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
235 return;
236
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200237 rettv->v_type = VAR_FLOAT;
238 if (get_float_arg(argvars, &f) == OK)
239 rettv->vval.v_float = cos(f);
240 else
241 rettv->vval.v_float = 0.0;
242}
243
244/*
245 * "cosh()" function
246 */
247 void
248f_cosh(typval_T *argvars, typval_T *rettv)
249{
250 float_T f = 0.0;
251
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200252 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
253 return;
254
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200255 rettv->v_type = VAR_FLOAT;
256 if (get_float_arg(argvars, &f) == OK)
257 rettv->vval.v_float = cosh(f);
258 else
259 rettv->vval.v_float = 0.0;
260}
261
262/*
263 * "exp()" function
264 */
265 void
266f_exp(typval_T *argvars, typval_T *rettv)
267{
268 float_T f = 0.0;
269
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200270 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
271 return;
272
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200273 rettv->v_type = VAR_FLOAT;
274 if (get_float_arg(argvars, &f) == OK)
275 rettv->vval.v_float = exp(f);
276 else
277 rettv->vval.v_float = 0.0;
278}
279
280/*
281 * "float2nr({float})" function
282 */
283 void
284f_float2nr(typval_T *argvars, typval_T *rettv)
285{
286 float_T f = 0.0;
287
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200288 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
289 return;
290
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +0000291 if (get_float_arg(argvars, &f) != OK)
292 return;
293
294 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
295 rettv->vval.v_number = -VARNUM_MAX;
296 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
297 rettv->vval.v_number = VARNUM_MAX;
298 else
299 rettv->vval.v_number = (varnumber_T)f;
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200300}
301
302/*
303 * "floor({float})" function
304 */
305 void
306f_floor(typval_T *argvars, typval_T *rettv)
307{
308 float_T f = 0.0;
309
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200310 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
311 return;
312
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200313 rettv->v_type = VAR_FLOAT;
314 if (get_float_arg(argvars, &f) == OK)
315 rettv->vval.v_float = floor(f);
316 else
317 rettv->vval.v_float = 0.0;
318}
319
320/*
321 * "fmod()" function
322 */
323 void
324f_fmod(typval_T *argvars, typval_T *rettv)
325{
326 float_T fx = 0.0, fy = 0.0;
327
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200328 if (in_vim9script()
329 && (check_for_float_or_nr_arg(argvars, 0) == FAIL
330 || check_for_float_or_nr_arg(argvars, 1) == FAIL))
331 return;
332
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200333 rettv->v_type = VAR_FLOAT;
334 if (get_float_arg(argvars, &fx) == OK
335 && get_float_arg(&argvars[1], &fy) == OK)
336 rettv->vval.v_float = fmod(fx, fy);
337 else
338 rettv->vval.v_float = 0.0;
339}
340
341# if defined(HAVE_MATH_H) || defined(PROTO)
342/*
343 * "isinf()" function
344 */
345 void
346f_isinf(typval_T *argvars, typval_T *rettv)
347{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200348 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
349 return;
350
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200351 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
352 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
353}
354
355/*
356 * "isnan()" function
357 */
358 void
359f_isnan(typval_T *argvars, typval_T *rettv)
360{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200361 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
362 return;
363
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200364 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
365 && isnan(argvars[0].vval.v_float);
366}
367# endif
368
369/*
370 * "log()" function
371 */
372 void
373f_log(typval_T *argvars, typval_T *rettv)
374{
375 float_T f = 0.0;
376
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200377 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
378 return;
379
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200380 rettv->v_type = VAR_FLOAT;
381 if (get_float_arg(argvars, &f) == OK)
382 rettv->vval.v_float = log(f);
383 else
384 rettv->vval.v_float = 0.0;
385}
386
387/*
388 * "log10()" function
389 */
390 void
391f_log10(typval_T *argvars, typval_T *rettv)
392{
393 float_T f = 0.0;
394
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200395 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
396 return;
397
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200398 rettv->v_type = VAR_FLOAT;
399 if (get_float_arg(argvars, &f) == OK)
400 rettv->vval.v_float = log10(f);
401 else
402 rettv->vval.v_float = 0.0;
403}
404
405/*
406 * "pow()" function
407 */
408 void
409f_pow(typval_T *argvars, typval_T *rettv)
410{
411 float_T fx = 0.0, fy = 0.0;
412
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200413 if (in_vim9script()
414 && (check_for_float_or_nr_arg(argvars, 0) == FAIL
415 || check_for_float_or_nr_arg(argvars, 1) == FAIL))
416 return;
417
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200418 rettv->v_type = VAR_FLOAT;
419 if (get_float_arg(argvars, &fx) == OK
420 && get_float_arg(&argvars[1], &fy) == OK)
421 rettv->vval.v_float = pow(fx, fy);
422 else
423 rettv->vval.v_float = 0.0;
424}
425
426
427/*
428 * round() is not in C90, use ceil() or floor() instead.
429 */
430 float_T
431vim_round(float_T f)
432{
433 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
434}
435
436/*
437 * "round({float})" function
438 */
439 void
440f_round(typval_T *argvars, typval_T *rettv)
441{
442 float_T f = 0.0;
443
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200444 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
445 return;
446
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200447 rettv->v_type = VAR_FLOAT;
448 if (get_float_arg(argvars, &f) == OK)
449 rettv->vval.v_float = vim_round(f);
450 else
451 rettv->vval.v_float = 0.0;
452}
453
454/*
455 * "sin()" function
456 */
457 void
458f_sin(typval_T *argvars, typval_T *rettv)
459{
460 float_T f = 0.0;
461
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200462 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
463 return;
464
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200465 rettv->v_type = VAR_FLOAT;
466 if (get_float_arg(argvars, &f) == OK)
467 rettv->vval.v_float = sin(f);
468 else
469 rettv->vval.v_float = 0.0;
470}
471
472/*
473 * "sinh()" function
474 */
475 void
476f_sinh(typval_T *argvars, typval_T *rettv)
477{
478 float_T f = 0.0;
479
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200480 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
481 return;
482
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200483 rettv->v_type = VAR_FLOAT;
484 if (get_float_arg(argvars, &f) == OK)
485 rettv->vval.v_float = sinh(f);
486 else
487 rettv->vval.v_float = 0.0;
488}
489
490/*
491 * "sqrt()" function
492 */
493 void
494f_sqrt(typval_T *argvars, typval_T *rettv)
495{
496 float_T f = 0.0;
497
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200498 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
499 return;
500
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200501 rettv->v_type = VAR_FLOAT;
502 if (get_float_arg(argvars, &f) == OK)
503 rettv->vval.v_float = sqrt(f);
504 else
505 rettv->vval.v_float = 0.0;
506}
507
508/*
509 * "str2float()" function
510 */
511 void
512f_str2float(typval_T *argvars, typval_T *rettv)
513{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200514 char_u *p;
515 int isneg;
Bram Moolenaar29500652021-08-08 15:43:34 +0200516 int skip_quotes;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200517
518 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
519 return;
520
Bram Moolenaar29500652021-08-08 15:43:34 +0200521 skip_quotes = argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]);
522
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200523 p = skipwhite(tv_get_string_strict(&argvars[0]));
524 isneg = (*p == '-');
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200525
526 if (*p == '+' || *p == '-')
527 p = skipwhite(p + 1);
Bram Moolenaar29500652021-08-08 15:43:34 +0200528 (void)string2float(p, &rettv->vval.v_float, skip_quotes);
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200529 if (isneg)
530 rettv->vval.v_float *= -1;
531 rettv->v_type = VAR_FLOAT;
532}
533
534/*
535 * "tan()" function
536 */
537 void
538f_tan(typval_T *argvars, typval_T *rettv)
539{
540 float_T f = 0.0;
541
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200542 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
543 return;
544
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200545 rettv->v_type = VAR_FLOAT;
546 if (get_float_arg(argvars, &f) == OK)
547 rettv->vval.v_float = tan(f);
548 else
549 rettv->vval.v_float = 0.0;
550}
551
552/*
553 * "tanh()" function
554 */
555 void
556f_tanh(typval_T *argvars, typval_T *rettv)
557{
558 float_T f = 0.0;
559
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200560 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
561 return;
562
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200563 rettv->v_type = VAR_FLOAT;
564 if (get_float_arg(argvars, &f) == OK)
565 rettv->vval.v_float = tanh(f);
566 else
567 rettv->vval.v_float = 0.0;
568}
569
570/*
571 * "trunc({float})" function
572 */
573 void
574f_trunc(typval_T *argvars, typval_T *rettv)
575{
576 float_T f = 0.0;
577
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200578 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
579 return;
580
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200581 rettv->v_type = VAR_FLOAT;
582 if (get_float_arg(argvars, &f) == OK)
583 // trunc() is not in C90, use floor() or ceil() instead.
584 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
585 else
586 rettv->vval.v_float = 0.0;
587}
588
589#endif