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