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 (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 86 return; 87 88 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 112 f_acos(typval_T *argvars, typval_T *rettv) 113 { 114 float_T f = 0.0; 115 116 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 117 return; 118 119 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 130 f_asin(typval_T *argvars, typval_T *rettv) 131 { 132 float_T f = 0.0; 133 134 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 135 return; 136 137 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 148 f_atan(typval_T *argvars, typval_T *rettv) 149 { 150 float_T f = 0.0; 151 152 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 153 return; 154 155 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 166 f_atan2(typval_T *argvars, typval_T *rettv) 167 { 168 float_T fx = 0.0, fy = 0.0; 169 170 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 175 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 187 f_ceil(typval_T *argvars, typval_T *rettv) 188 { 189 float_T f = 0.0; 190 191 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 192 return; 193 194 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 205 f_cos(typval_T *argvars, typval_T *rettv) 206 { 207 float_T f = 0.0; 208 209 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 210 return; 211 212 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 223 f_cosh(typval_T *argvars, typval_T *rettv) 224 { 225 float_T f = 0.0; 226 227 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 228 return; 229 230 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 241 f_exp(typval_T *argvars, typval_T *rettv) 242 { 243 float_T f = 0.0; 244 245 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 246 return; 247 248 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 259 f_float2nr(typval_T *argvars, typval_T *rettv) 260 { 261 float_T f = 0.0; 262 263 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 264 return; 265 266 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 281 f_floor(typval_T *argvars, typval_T *rettv) 282 { 283 float_T f = 0.0; 284 285 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 286 return; 287 288 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 299 f_fmod(typval_T *argvars, typval_T *rettv) 300 { 301 float_T fx = 0.0, fy = 0.0; 302 303 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 308 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 321 f_isinf(typval_T *argvars, typval_T *rettv) 322 { 323 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 324 return; 325 326 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 334 f_isnan(typval_T *argvars, typval_T *rettv) 335 { 336 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 337 return; 338 339 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 348 f_log(typval_T *argvars, typval_T *rettv) 349 { 350 float_T f = 0.0; 351 352 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 353 return; 354 355 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 366 f_log10(typval_T *argvars, typval_T *rettv) 367 { 368 float_T f = 0.0; 369 370 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 371 return; 372 373 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 384 f_pow(typval_T *argvars, typval_T *rettv) 385 { 386 float_T fx = 0.0, fy = 0.0; 387 388 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 393 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 406 vim_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 415 f_round(typval_T *argvars, typval_T *rettv) 416 { 417 float_T f = 0.0; 418 419 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 420 return; 421 422 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 433 f_sin(typval_T *argvars, typval_T *rettv) 434 { 435 float_T f = 0.0; 436 437 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 438 return; 439 440 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 451 f_sinh(typval_T *argvars, typval_T *rettv) 452 { 453 float_T f = 0.0; 454 455 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 456 return; 457 458 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 469 f_sqrt(typval_T *argvars, typval_T *rettv) 470 { 471 float_T f = 0.0; 472 473 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 474 return; 475 476 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 487 f_str2float(typval_T *argvars, typval_T *rettv) 488 { 489 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 == '-'); 497 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 510 f_tan(typval_T *argvars, typval_T *rettv) 511 { 512 float_T f = 0.0; 513 514 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 515 return; 516 517 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 528 f_tanh(typval_T *argvars, typval_T *rettv) 529 { 530 float_T f = 0.0; 531 532 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 533 return; 534 535 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 546 f_trunc(typval_T *argvars, typval_T *rettv) 547 { 548 float_T f = 0.0; 549 550 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 551 return; 552 553 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 562