xref: /vim-8.2.3635/src/float.c (revision f573c6e1)
1 /* 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
30 string2float(
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
63 get_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
83 f_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
109 f_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
124 f_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
139 f_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
154 f_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
170 f_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
185 f_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
200 f_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
215 f_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
230 f_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
249 f_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
264 f_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
281 f_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
291 f_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
302 f_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
317 f_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
332 f_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
349 vim_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
358 f_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
373 f_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
388 f_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
403 f_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
418 f_str2float(typval_T *argvars, typval_T *rettv)
419 {
420     char_u *p = skipwhite(tv_get_string_strict(&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
435 f_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
450 f_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
465 f_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
478