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 int skip_quotes) 34 { 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 } 44 if (STRNICMP(text, "-inf", 3) == 0) 45 { 46 *value = -INFINITY; 47 return 4; 48 } 49 if (STRNICMP(text, "nan", 3) == 0) 50 { 51 *value = NAN; 52 return 3; 53 } 54 if (skip_quotes && vim_strchr((char_u *)s, '\'') != NULL) 55 { 56 char_u buf[100]; 57 char_u *p = buf; 58 int quotes = 0; 59 60 vim_strncpy(buf, (char_u *)s, 99); 61 p = buf; 62 for (;;) 63 { 64 // remove single quotes between digits, not in the exponent 65 if (*p == '\'') 66 { 67 ++quotes; 68 mch_memmove(p, p + 1, STRLEN(p)); 69 } 70 if (!vim_isdigit(*p)) 71 break; 72 p = skipdigits(p); 73 } 74 s = (char *)buf; 75 f = strtod(s, &s); 76 *value = f; 77 return (int)((char_u *)s - buf) + quotes; 78 } 79 80 f = strtod(s, &s); 81 *value = f; 82 return (int)((char_u *)s - text); 83 } 84 85 /* 86 * Get the float value of "argvars[0]" into "f". 87 * Returns FAIL when the argument is not a Number or Float. 88 */ 89 static int 90 get_float_arg(typval_T *argvars, float_T *f) 91 { 92 if (argvars[0].v_type == VAR_FLOAT) 93 { 94 *f = argvars[0].vval.v_float; 95 return OK; 96 } 97 if (argvars[0].v_type == VAR_NUMBER) 98 { 99 *f = (float_T)argvars[0].vval.v_number; 100 return OK; 101 } 102 emsg(_("E808: Number or Float required")); 103 return FAIL; 104 } 105 106 /* 107 * "abs(expr)" function 108 */ 109 void 110 f_abs(typval_T *argvars, typval_T *rettv) 111 { 112 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 113 return; 114 115 if (argvars[0].v_type == VAR_FLOAT) 116 { 117 rettv->v_type = VAR_FLOAT; 118 rettv->vval.v_float = fabs(argvars[0].vval.v_float); 119 } 120 else 121 { 122 varnumber_T n; 123 int error = FALSE; 124 125 n = tv_get_number_chk(&argvars[0], &error); 126 if (error) 127 rettv->vval.v_number = -1; 128 else if (n > 0) 129 rettv->vval.v_number = n; 130 else 131 rettv->vval.v_number = -n; 132 } 133 } 134 135 /* 136 * "acos()" function 137 */ 138 void 139 f_acos(typval_T *argvars, typval_T *rettv) 140 { 141 float_T f = 0.0; 142 143 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 144 return; 145 146 rettv->v_type = VAR_FLOAT; 147 if (get_float_arg(argvars, &f) == OK) 148 rettv->vval.v_float = acos(f); 149 else 150 rettv->vval.v_float = 0.0; 151 } 152 153 /* 154 * "asin()" function 155 */ 156 void 157 f_asin(typval_T *argvars, typval_T *rettv) 158 { 159 float_T f = 0.0; 160 161 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 162 return; 163 164 rettv->v_type = VAR_FLOAT; 165 if (get_float_arg(argvars, &f) == OK) 166 rettv->vval.v_float = asin(f); 167 else 168 rettv->vval.v_float = 0.0; 169 } 170 171 /* 172 * "atan()" function 173 */ 174 void 175 f_atan(typval_T *argvars, typval_T *rettv) 176 { 177 float_T f = 0.0; 178 179 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 180 return; 181 182 rettv->v_type = VAR_FLOAT; 183 if (get_float_arg(argvars, &f) == OK) 184 rettv->vval.v_float = atan(f); 185 else 186 rettv->vval.v_float = 0.0; 187 } 188 189 /* 190 * "atan2()" function 191 */ 192 void 193 f_atan2(typval_T *argvars, typval_T *rettv) 194 { 195 float_T fx = 0.0, fy = 0.0; 196 197 if (in_vim9script() 198 && (check_for_float_or_nr_arg(argvars, 0) == FAIL 199 || check_for_float_or_nr_arg(argvars, 1) == FAIL)) 200 return; 201 202 rettv->v_type = VAR_FLOAT; 203 if (get_float_arg(argvars, &fx) == OK 204 && get_float_arg(&argvars[1], &fy) == OK) 205 rettv->vval.v_float = atan2(fx, fy); 206 else 207 rettv->vval.v_float = 0.0; 208 } 209 210 /* 211 * "ceil({float})" function 212 */ 213 void 214 f_ceil(typval_T *argvars, typval_T *rettv) 215 { 216 float_T f = 0.0; 217 218 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 219 return; 220 221 rettv->v_type = VAR_FLOAT; 222 if (get_float_arg(argvars, &f) == OK) 223 rettv->vval.v_float = ceil(f); 224 else 225 rettv->vval.v_float = 0.0; 226 } 227 228 /* 229 * "cos()" function 230 */ 231 void 232 f_cos(typval_T *argvars, typval_T *rettv) 233 { 234 float_T f = 0.0; 235 236 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 237 return; 238 239 rettv->v_type = VAR_FLOAT; 240 if (get_float_arg(argvars, &f) == OK) 241 rettv->vval.v_float = cos(f); 242 else 243 rettv->vval.v_float = 0.0; 244 } 245 246 /* 247 * "cosh()" function 248 */ 249 void 250 f_cosh(typval_T *argvars, typval_T *rettv) 251 { 252 float_T f = 0.0; 253 254 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 255 return; 256 257 rettv->v_type = VAR_FLOAT; 258 if (get_float_arg(argvars, &f) == OK) 259 rettv->vval.v_float = cosh(f); 260 else 261 rettv->vval.v_float = 0.0; 262 } 263 264 /* 265 * "exp()" function 266 */ 267 void 268 f_exp(typval_T *argvars, typval_T *rettv) 269 { 270 float_T f = 0.0; 271 272 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 273 return; 274 275 rettv->v_type = VAR_FLOAT; 276 if (get_float_arg(argvars, &f) == OK) 277 rettv->vval.v_float = exp(f); 278 else 279 rettv->vval.v_float = 0.0; 280 } 281 282 /* 283 * "float2nr({float})" function 284 */ 285 void 286 f_float2nr(typval_T *argvars, typval_T *rettv) 287 { 288 float_T f = 0.0; 289 290 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 291 return; 292 293 if (get_float_arg(argvars, &f) == OK) 294 { 295 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON) 296 rettv->vval.v_number = -VARNUM_MAX; 297 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON) 298 rettv->vval.v_number = VARNUM_MAX; 299 else 300 rettv->vval.v_number = (varnumber_T)f; 301 } 302 } 303 304 /* 305 * "floor({float})" function 306 */ 307 void 308 f_floor(typval_T *argvars, typval_T *rettv) 309 { 310 float_T f = 0.0; 311 312 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 313 return; 314 315 rettv->v_type = VAR_FLOAT; 316 if (get_float_arg(argvars, &f) == OK) 317 rettv->vval.v_float = floor(f); 318 else 319 rettv->vval.v_float = 0.0; 320 } 321 322 /* 323 * "fmod()" function 324 */ 325 void 326 f_fmod(typval_T *argvars, typval_T *rettv) 327 { 328 float_T fx = 0.0, fy = 0.0; 329 330 if (in_vim9script() 331 && (check_for_float_or_nr_arg(argvars, 0) == FAIL 332 || check_for_float_or_nr_arg(argvars, 1) == FAIL)) 333 return; 334 335 rettv->v_type = VAR_FLOAT; 336 if (get_float_arg(argvars, &fx) == OK 337 && get_float_arg(&argvars[1], &fy) == OK) 338 rettv->vval.v_float = fmod(fx, fy); 339 else 340 rettv->vval.v_float = 0.0; 341 } 342 343 # if defined(HAVE_MATH_H) || defined(PROTO) 344 /* 345 * "isinf()" function 346 */ 347 void 348 f_isinf(typval_T *argvars, typval_T *rettv) 349 { 350 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 351 return; 352 353 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float)) 354 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1; 355 } 356 357 /* 358 * "isnan()" function 359 */ 360 void 361 f_isnan(typval_T *argvars, typval_T *rettv) 362 { 363 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 364 return; 365 366 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT 367 && isnan(argvars[0].vval.v_float); 368 } 369 # endif 370 371 /* 372 * "log()" function 373 */ 374 void 375 f_log(typval_T *argvars, typval_T *rettv) 376 { 377 float_T f = 0.0; 378 379 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 380 return; 381 382 rettv->v_type = VAR_FLOAT; 383 if (get_float_arg(argvars, &f) == OK) 384 rettv->vval.v_float = log(f); 385 else 386 rettv->vval.v_float = 0.0; 387 } 388 389 /* 390 * "log10()" function 391 */ 392 void 393 f_log10(typval_T *argvars, typval_T *rettv) 394 { 395 float_T f = 0.0; 396 397 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 398 return; 399 400 rettv->v_type = VAR_FLOAT; 401 if (get_float_arg(argvars, &f) == OK) 402 rettv->vval.v_float = log10(f); 403 else 404 rettv->vval.v_float = 0.0; 405 } 406 407 /* 408 * "pow()" function 409 */ 410 void 411 f_pow(typval_T *argvars, typval_T *rettv) 412 { 413 float_T fx = 0.0, fy = 0.0; 414 415 if (in_vim9script() 416 && (check_for_float_or_nr_arg(argvars, 0) == FAIL 417 || check_for_float_or_nr_arg(argvars, 1) == FAIL)) 418 return; 419 420 rettv->v_type = VAR_FLOAT; 421 if (get_float_arg(argvars, &fx) == OK 422 && get_float_arg(&argvars[1], &fy) == OK) 423 rettv->vval.v_float = pow(fx, fy); 424 else 425 rettv->vval.v_float = 0.0; 426 } 427 428 429 /* 430 * round() is not in C90, use ceil() or floor() instead. 431 */ 432 float_T 433 vim_round(float_T f) 434 { 435 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5); 436 } 437 438 /* 439 * "round({float})" function 440 */ 441 void 442 f_round(typval_T *argvars, typval_T *rettv) 443 { 444 float_T f = 0.0; 445 446 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 447 return; 448 449 rettv->v_type = VAR_FLOAT; 450 if (get_float_arg(argvars, &f) == OK) 451 rettv->vval.v_float = vim_round(f); 452 else 453 rettv->vval.v_float = 0.0; 454 } 455 456 /* 457 * "sin()" function 458 */ 459 void 460 f_sin(typval_T *argvars, typval_T *rettv) 461 { 462 float_T f = 0.0; 463 464 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 465 return; 466 467 rettv->v_type = VAR_FLOAT; 468 if (get_float_arg(argvars, &f) == OK) 469 rettv->vval.v_float = sin(f); 470 else 471 rettv->vval.v_float = 0.0; 472 } 473 474 /* 475 * "sinh()" function 476 */ 477 void 478 f_sinh(typval_T *argvars, typval_T *rettv) 479 { 480 float_T f = 0.0; 481 482 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 483 return; 484 485 rettv->v_type = VAR_FLOAT; 486 if (get_float_arg(argvars, &f) == OK) 487 rettv->vval.v_float = sinh(f); 488 else 489 rettv->vval.v_float = 0.0; 490 } 491 492 /* 493 * "sqrt()" function 494 */ 495 void 496 f_sqrt(typval_T *argvars, typval_T *rettv) 497 { 498 float_T f = 0.0; 499 500 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 501 return; 502 503 rettv->v_type = VAR_FLOAT; 504 if (get_float_arg(argvars, &f) == OK) 505 rettv->vval.v_float = sqrt(f); 506 else 507 rettv->vval.v_float = 0.0; 508 } 509 510 /* 511 * "str2float()" function 512 */ 513 void 514 f_str2float(typval_T *argvars, typval_T *rettv) 515 { 516 char_u *p; 517 int isneg; 518 int skip_quotes; 519 520 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) 521 return; 522 523 skip_quotes = argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]); 524 525 p = skipwhite(tv_get_string_strict(&argvars[0])); 526 isneg = (*p == '-'); 527 528 if (*p == '+' || *p == '-') 529 p = skipwhite(p + 1); 530 (void)string2float(p, &rettv->vval.v_float, skip_quotes); 531 if (isneg) 532 rettv->vval.v_float *= -1; 533 rettv->v_type = VAR_FLOAT; 534 } 535 536 /* 537 * "tan()" function 538 */ 539 void 540 f_tan(typval_T *argvars, typval_T *rettv) 541 { 542 float_T f = 0.0; 543 544 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 545 return; 546 547 rettv->v_type = VAR_FLOAT; 548 if (get_float_arg(argvars, &f) == OK) 549 rettv->vval.v_float = tan(f); 550 else 551 rettv->vval.v_float = 0.0; 552 } 553 554 /* 555 * "tanh()" function 556 */ 557 void 558 f_tanh(typval_T *argvars, typval_T *rettv) 559 { 560 float_T f = 0.0; 561 562 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 563 return; 564 565 rettv->v_type = VAR_FLOAT; 566 if (get_float_arg(argvars, &f) == OK) 567 rettv->vval.v_float = tanh(f); 568 else 569 rettv->vval.v_float = 0.0; 570 } 571 572 /* 573 * "trunc({float})" function 574 */ 575 void 576 f_trunc(typval_T *argvars, typval_T *rettv) 577 { 578 float_T f = 0.0; 579 580 if (in_vim9script() && check_for_float_or_nr_arg(argvars, 0) == FAIL) 581 return; 582 583 rettv->v_type = VAR_FLOAT; 584 if (get_float_arg(argvars, &f) == OK) 585 // trunc() is not in C90, use floor() or ceil() instead. 586 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f); 587 else 588 rettv->vval.v_float = 0.0; 589 } 590 591 #endif 592