blob: 898095fd4b6274b7c43f774c4a611489329a094d [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{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +020085 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
86 return;
87
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +020088 if (argvars[0].v_type == VAR_FLOAT)
89 {
90 rettv->v_type = VAR_FLOAT;
91 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
92 }
93 else
94 {
95 varnumber_T n;
96 int error = FALSE;
97
98 n = tv_get_number_chk(&argvars[0], &error);
99 if (error)
100 rettv->vval.v_number = -1;
101 else if (n > 0)
102 rettv->vval.v_number = n;
103 else
104 rettv->vval.v_number = -n;
105 }
106}
107
108/*
109 * "acos()" function
110 */
111 void
112f_acos(typval_T *argvars, typval_T *rettv)
113{
114 float_T f = 0.0;
115
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200116 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
117 return;
118
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200119 rettv->v_type = VAR_FLOAT;
120 if (get_float_arg(argvars, &f) == OK)
121 rettv->vval.v_float = acos(f);
122 else
123 rettv->vval.v_float = 0.0;
124}
125
126/*
127 * "asin()" function
128 */
129 void
130f_asin(typval_T *argvars, typval_T *rettv)
131{
132 float_T f = 0.0;
133
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200134 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
135 return;
136
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200137 rettv->v_type = VAR_FLOAT;
138 if (get_float_arg(argvars, &f) == OK)
139 rettv->vval.v_float = asin(f);
140 else
141 rettv->vval.v_float = 0.0;
142}
143
144/*
145 * "atan()" function
146 */
147 void
148f_atan(typval_T *argvars, typval_T *rettv)
149{
150 float_T f = 0.0;
151
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200152 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
153 return;
154
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200155 rettv->v_type = VAR_FLOAT;
156 if (get_float_arg(argvars, &f) == OK)
157 rettv->vval.v_float = atan(f);
158 else
159 rettv->vval.v_float = 0.0;
160}
161
162/*
163 * "atan2()" function
164 */
165 void
166f_atan2(typval_T *argvars, typval_T *rettv)
167{
168 float_T fx = 0.0, fy = 0.0;
169
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200170 if (in_vim9script()
171 && (check_for_float_or_nr_arg(argvars, 0) == FAIL
172 || check_for_float_or_nr_arg(argvars, 1) == FAIL))
173 return;
174
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200175 rettv->v_type = VAR_FLOAT;
176 if (get_float_arg(argvars, &fx) == OK
177 && get_float_arg(&argvars[1], &fy) == OK)
178 rettv->vval.v_float = atan2(fx, fy);
179 else
180 rettv->vval.v_float = 0.0;
181}
182
183/*
184 * "ceil({float})" function
185 */
186 void
187f_ceil(typval_T *argvars, typval_T *rettv)
188{
189 float_T f = 0.0;
190
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200191 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
192 return;
193
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200194 rettv->v_type = VAR_FLOAT;
195 if (get_float_arg(argvars, &f) == OK)
196 rettv->vval.v_float = ceil(f);
197 else
198 rettv->vval.v_float = 0.0;
199}
200
201/*
202 * "cos()" function
203 */
204 void
205f_cos(typval_T *argvars, typval_T *rettv)
206{
207 float_T f = 0.0;
208
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200209 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
210 return;
211
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200212 rettv->v_type = VAR_FLOAT;
213 if (get_float_arg(argvars, &f) == OK)
214 rettv->vval.v_float = cos(f);
215 else
216 rettv->vval.v_float = 0.0;
217}
218
219/*
220 * "cosh()" function
221 */
222 void
223f_cosh(typval_T *argvars, typval_T *rettv)
224{
225 float_T f = 0.0;
226
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200227 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
228 return;
229
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200230 rettv->v_type = VAR_FLOAT;
231 if (get_float_arg(argvars, &f) == OK)
232 rettv->vval.v_float = cosh(f);
233 else
234 rettv->vval.v_float = 0.0;
235}
236
237/*
238 * "exp()" function
239 */
240 void
241f_exp(typval_T *argvars, typval_T *rettv)
242{
243 float_T f = 0.0;
244
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200245 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
246 return;
247
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200248 rettv->v_type = VAR_FLOAT;
249 if (get_float_arg(argvars, &f) == OK)
250 rettv->vval.v_float = exp(f);
251 else
252 rettv->vval.v_float = 0.0;
253}
254
255/*
256 * "float2nr({float})" function
257 */
258 void
259f_float2nr(typval_T *argvars, typval_T *rettv)
260{
261 float_T f = 0.0;
262
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200263 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
264 return;
265
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200266 if (get_float_arg(argvars, &f) == OK)
267 {
268 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
269 rettv->vval.v_number = -VARNUM_MAX;
270 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
271 rettv->vval.v_number = VARNUM_MAX;
272 else
273 rettv->vval.v_number = (varnumber_T)f;
274 }
275}
276
277/*
278 * "floor({float})" function
279 */
280 void
281f_floor(typval_T *argvars, typval_T *rettv)
282{
283 float_T f = 0.0;
284
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200285 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
286 return;
287
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200288 rettv->v_type = VAR_FLOAT;
289 if (get_float_arg(argvars, &f) == OK)
290 rettv->vval.v_float = floor(f);
291 else
292 rettv->vval.v_float = 0.0;
293}
294
295/*
296 * "fmod()" function
297 */
298 void
299f_fmod(typval_T *argvars, typval_T *rettv)
300{
301 float_T fx = 0.0, fy = 0.0;
302
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200303 if (in_vim9script()
304 && (check_for_float_or_nr_arg(argvars, 0) == FAIL
305 || check_for_float_or_nr_arg(argvars, 1) == FAIL))
306 return;
307
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200308 rettv->v_type = VAR_FLOAT;
309 if (get_float_arg(argvars, &fx) == OK
310 && get_float_arg(&argvars[1], &fy) == OK)
311 rettv->vval.v_float = fmod(fx, fy);
312 else
313 rettv->vval.v_float = 0.0;
314}
315
316# if defined(HAVE_MATH_H) || defined(PROTO)
317/*
318 * "isinf()" function
319 */
320 void
321f_isinf(typval_T *argvars, typval_T *rettv)
322{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200323 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
324 return;
325
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200326 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
327 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
328}
329
330/*
331 * "isnan()" function
332 */
333 void
334f_isnan(typval_T *argvars, typval_T *rettv)
335{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200336 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
337 return;
338
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200339 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
340 && isnan(argvars[0].vval.v_float);
341}
342# endif
343
344/*
345 * "log()" function
346 */
347 void
348f_log(typval_T *argvars, typval_T *rettv)
349{
350 float_T f = 0.0;
351
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200352 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
353 return;
354
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200355 rettv->v_type = VAR_FLOAT;
356 if (get_float_arg(argvars, &f) == OK)
357 rettv->vval.v_float = log(f);
358 else
359 rettv->vval.v_float = 0.0;
360}
361
362/*
363 * "log10()" function
364 */
365 void
366f_log10(typval_T *argvars, typval_T *rettv)
367{
368 float_T f = 0.0;
369
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200370 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
371 return;
372
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200373 rettv->v_type = VAR_FLOAT;
374 if (get_float_arg(argvars, &f) == OK)
375 rettv->vval.v_float = log10(f);
376 else
377 rettv->vval.v_float = 0.0;
378}
379
380/*
381 * "pow()" function
382 */
383 void
384f_pow(typval_T *argvars, typval_T *rettv)
385{
386 float_T fx = 0.0, fy = 0.0;
387
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200388 if (in_vim9script()
389 && (check_for_float_or_nr_arg(argvars, 0) == FAIL
390 || check_for_float_or_nr_arg(argvars, 1) == FAIL))
391 return;
392
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200393 rettv->v_type = VAR_FLOAT;
394 if (get_float_arg(argvars, &fx) == OK
395 && get_float_arg(&argvars[1], &fy) == OK)
396 rettv->vval.v_float = pow(fx, fy);
397 else
398 rettv->vval.v_float = 0.0;
399}
400
401
402/*
403 * round() is not in C90, use ceil() or floor() instead.
404 */
405 float_T
406vim_round(float_T f)
407{
408 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
409}
410
411/*
412 * "round({float})" function
413 */
414 void
415f_round(typval_T *argvars, typval_T *rettv)
416{
417 float_T f = 0.0;
418
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200419 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
420 return;
421
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200422 rettv->v_type = VAR_FLOAT;
423 if (get_float_arg(argvars, &f) == OK)
424 rettv->vval.v_float = vim_round(f);
425 else
426 rettv->vval.v_float = 0.0;
427}
428
429/*
430 * "sin()" function
431 */
432 void
433f_sin(typval_T *argvars, typval_T *rettv)
434{
435 float_T f = 0.0;
436
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200437 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
438 return;
439
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200440 rettv->v_type = VAR_FLOAT;
441 if (get_float_arg(argvars, &f) == OK)
442 rettv->vval.v_float = sin(f);
443 else
444 rettv->vval.v_float = 0.0;
445}
446
447/*
448 * "sinh()" function
449 */
450 void
451f_sinh(typval_T *argvars, typval_T *rettv)
452{
453 float_T f = 0.0;
454
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200455 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
456 return;
457
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200458 rettv->v_type = VAR_FLOAT;
459 if (get_float_arg(argvars, &f) == OK)
460 rettv->vval.v_float = sinh(f);
461 else
462 rettv->vval.v_float = 0.0;
463}
464
465/*
466 * "sqrt()" function
467 */
468 void
469f_sqrt(typval_T *argvars, typval_T *rettv)
470{
471 float_T f = 0.0;
472
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200473 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
474 return;
475
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200476 rettv->v_type = VAR_FLOAT;
477 if (get_float_arg(argvars, &f) == OK)
478 rettv->vval.v_float = sqrt(f);
479 else
480 rettv->vval.v_float = 0.0;
481}
482
483/*
484 * "str2float()" function
485 */
486 void
487f_str2float(typval_T *argvars, typval_T *rettv)
488{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200489 char_u *p;
490 int isneg;
491
492 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
493 return;
494
495 p = skipwhite(tv_get_string_strict(&argvars[0]));
496 isneg = (*p == '-');
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200497
498 if (*p == '+' || *p == '-')
499 p = skipwhite(p + 1);
500 (void)string2float(p, &rettv->vval.v_float);
501 if (isneg)
502 rettv->vval.v_float *= -1;
503 rettv->v_type = VAR_FLOAT;
504}
505
506/*
507 * "tan()" function
508 */
509 void
510f_tan(typval_T *argvars, typval_T *rettv)
511{
512 float_T f = 0.0;
513
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200514 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
515 return;
516
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200517 rettv->v_type = VAR_FLOAT;
518 if (get_float_arg(argvars, &f) == OK)
519 rettv->vval.v_float = tan(f);
520 else
521 rettv->vval.v_float = 0.0;
522}
523
524/*
525 * "tanh()" function
526 */
527 void
528f_tanh(typval_T *argvars, typval_T *rettv)
529{
530 float_T f = 0.0;
531
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200532 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
533 return;
534
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200535 rettv->v_type = VAR_FLOAT;
536 if (get_float_arg(argvars, &f) == OK)
537 rettv->vval.v_float = tanh(f);
538 else
539 rettv->vval.v_float = 0.0;
540}
541
542/*
543 * "trunc({float})" function
544 */
545 void
546f_trunc(typval_T *argvars, typval_T *rettv)
547{
548 float_T f = 0.0;
549
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200550 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL)
551 return;
552
Yegappan Lakshmanan01c798c2021-06-02 17:07:18 +0200553 rettv->v_type = VAR_FLOAT;
554 if (get_float_arg(argvars, &f) == OK)
555 // trunc() is not in C90, use floor() or ceil() instead.
556 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
557 else
558 rettv->vval.v_float = 0.0;
559}
560
561#endif