1 /* 2 * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /** 18 * # Mathematical Functions 19 * 20 * The `math` module bundles various mathematical and trigonometrical functions. 21 * 22 * Functions can be individually imported and directly accessed using the 23 * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#named_import named import} 24 * syntax: 25 * 26 * ``` 27 * import { pow, rand } from 'math'; 28 * 29 * let x = pow(2, 5); 30 * let y = rand(); 31 * ``` 32 * 33 * Alternatively, the module namespace can be imported 34 * using a wildcard import statement: 35 * 36 * ``` 37 * import * as math from 'math'; 38 * 39 * let x = math.pow(2, 5); 40 * let y = math.rand(); 41 * ``` 42 * 43 * Additionally, the math module namespace may also be imported by invoking the 44 * `ucode` interpreter with the `-lmath` switch. 45 * 46 * It should be noted that when the ucode interpreter is run as `-p "..."`, 47 * values involving Infinity are returned as the max double precision value 48 * +/-1e309 (JSON), whereas when run as `-e "print(...)"` Infinity is 49 * represented by the string `Infinity`. The boolean check `isinf()` is 50 * available to determine Infinity values. 51 * 52 * @module math 53 */ 54 55 #include <math.h> 56 #include <errno.h> 57 #include <sys/time.h> 58 59 #include "ucode/module.h" 60 61 #ifndef M_PI 62 #define M_PI 3.14159265358979323846264338327950288 63 #endif 64 #define degToRad(angleInDegrees) ((angleInDegrees) * M_PI / 180.0) 65 #define radToDeg(angleInRadians) ((angleInRadians) * 180.0 / M_PI) 66 67 68 /** 69 * Returns the absolute value of the given numeric value. 70 * 71 * @function module:math#abs 72 * 73 * @param {*} number 74 * The number to return the absolute value for. 75 * 76 * @returns {number} 77 * Returns the absolute value or `NaN` if the given argument could 78 * not be converted to a number. 79 */ 80 static uc_value_t * 81 uc_abs(uc_vm_t *vm, size_t nargs) 82 { 83 uc_value_t *v = uc_fn_arg(0), *nv, *res; 84 int64_t n; 85 double d; 86 87 nv = v ? ucv_to_number(v) : NULL; 88 89 switch (ucv_type(nv)) { 90 case UC_INTEGER: 91 n = ucv_int64_get(nv); 92 93 if (n >= 0 || errno == ERANGE) 94 res = ucv_get(nv); 95 else if (n == INT64_MIN) 96 res = ucv_uint64_new((uint64_t)INT64_MAX + 1); 97 else 98 res = ucv_uint64_new(-n); 99 100 break; 101 102 case UC_DOUBLE: 103 d = ucv_double_get(nv); 104 105 if (isnan(d) || d >= 0) 106 res = ucv_get(nv); 107 else 108 res = ucv_double_new(-d); 109 110 break; 111 112 default: 113 res = ucv_double_new(NAN); 114 break; 115 } 116 117 ucv_put(nv); 118 119 return res; 120 } 121 122 /** 123 * Calculates the arc cosine of `x`. 124 * 125 * On success, this function returns the principal value of the arc 126 * cosine of `x` in radians; the return value is in the range [pi, 0]. 127 * 128 * - If `x` is -1, pi is returned. 129 * - If `x` is 0, pi/2 is returned. 130 * - If `x` is +1, 0 is returned. 131 * 132 * When `x` can't be converted to a numeric value, `NaN` is 133 * returned. 134 * 135 * @function module:math#acos 136 * 137 * @param {double} x 138 * The `x` value. 139 * 140 * @returns {double} 141 * @example 142 * acos(-1); // 3.1415926535898 i.e. pi 143 * acos(0); // 1.5707963267949 i.e. pi/2 144 * acos(1); // 0.0 i.e. 0 pi 145 */ 146 static uc_value_t * 147 uc_arccos(uc_vm_t *vm, size_t nargs) 148 { 149 double x = ucv_to_double(uc_fn_arg(0)); 150 151 if (isnan(x)) 152 return ucv_double_new(NAN); 153 154 return ucv_double_new(acos(x)); 155 } 156 157 /** 158 * Calculates the arc sine of `x`. 159 * 160 * On success, this function returns the principal value of the arc 161 * sine of `x` in radians; the return value is in the range [-pi/2, pi/2]. 162 * 163 * - If `x` is +0 (-0), 0 is returned. 164 * - If `x` is +1 (-1), pi/2 (-pi/2) is returned. 165 * 166 * When `x` can't be converted to a numeric value, `NaN` is 167 * returned. 168 * 169 * @function module:math#asin 170 * 171 * @param {double} x 172 * The `x` value. 173 * 174 * @returns {double} 175 * @example 176 * asin(-1); // -1.5707963267949 i.e. -pi/2 177 * asin(0); // 0.0 i.e. 0 pi 178 * asin(1); // 1.5707963267949 i.e. pi/2 179 */ 180 static uc_value_t * 181 uc_arcsin(uc_vm_t *vm, size_t nargs) 182 { 183 double x = ucv_to_double(uc_fn_arg(0)); 184 185 if (isnan(x)) 186 return ucv_double_new(NAN); 187 188 return ucv_double_new(asin(x)); 189 } 190 191 /** 192 * Calculates the arc tangent of `x`. 193 * 194 * On success, this function returns the principal value of the arc 195 * tangent of `x` in radians; the return value is in the range [-pi/2, pi/2]. 196 * 197 * - If `x` is +0 (-0), 0 is returned. 198 * - As `x` tends toward +Infinity (-Infinity), the return value asymptotically 199 * converges toward pi/2 (-pi/2). 200 * 201 * When `x` can't be converted to a numeric value, `NaN` is 202 * returned. 203 * 204 * @function module:math#atan 205 * 206 * @param {double} x 207 * The `x` value. 208 * 209 * @returns {double} 210 * @example 211 * atan(-100000); // -1.5707863267949 i.e. ~ -pi/2 212 * atan(0); // 0.0 i.e. 0 pi 213 * atan(100000); // 1.5707863267949 i.e. ~ pi/2 214 */ 215 static uc_value_t * 216 uc_arctan(uc_vm_t *vm, size_t nargs) 217 { 218 double x = ucv_to_double(uc_fn_arg(0)); 219 220 if (isnan(x)) 221 return ucv_double_new(NAN); 222 223 return ucv_double_new(atan(x)); 224 } 225 226 /** 227 * Calculates the hyperbolic cosine of `x`. 228 * 229 * On success, this function returns the principal value of the hyperbolic 230 * cosine of `x`; the return value is in the range [Infinity, 1]. 231 * 232 * The relationship is: cosh = `((e^x) + (e^-x)) / 2`. 233 * 234 * - As `x` decreases below -1, the return value exponentiates toward Infinity. 235 * - If `x` is 0, 1 is returned. 236 * - As `x` increases above +1, the return value exponentiates toward Infinity. 237 * 238 * When `x` can't be converted to a numeric value, `NaN` is 239 * returned. 240 * 241 * @function module:math#cosh 242 * 243 * @param {double} x 244 * The `x` value. 245 * 246 * @returns {double} 247 * @example 248 * cosh(-10); // 11013.232920103 249 * cosh(-1); // 1.5430806348152 250 * cosh(0); // 1.0 251 * cosh(1); // 1.5430806348152 252 * cosh(10); // 11013.232920103 253 */ 254 static uc_value_t * 255 uc_cosh(uc_vm_t *vm, size_t nargs) 256 { 257 double x = ucv_to_double(uc_fn_arg(0)); 258 259 if (isnan(x)) 260 return ucv_double_new(NAN); 261 262 return ucv_double_new(cosh(x)); 263 } 264 265 /** 266 * Calculates the hyperbolic sine of `x`. 267 * 268 * On success, this function returns the principal value of the hyperbolic 269 * sine of `x`; the return value is in the range [-Infinity, Infinity]. 270 * 271 * The relationship is: sinh = `((e^x) - (e^-x)) / 2`. 272 * 273 * - As `x` decreases below -1, the return value exponentiates toward -Infinity. 274 * - If `x` is 0, 0 is returned. 275 * - As `x` increases above +1, the return value exponentiates toward Infinity. 276 * 277 * When `x` can't be converted to a numeric value, `NaN` is 278 * returned. 279 * 280 * @function module:math#sinh 281 * 282 * @param {double} x 283 * The `x` value. 284 * 285 * @returns {double} 286 * @example 287 * sinh(-10); // -11013.232920103 288 * sinh(-1); // -1.1752011936438 289 * sinh(0); // 0.0 290 * sinh(1); // 1.1752011936438 291 * sinh(10); // 11013.232920103 292 */ 293 static uc_value_t * 294 uc_sinh(uc_vm_t *vm, size_t nargs) 295 { 296 double x = ucv_to_double(uc_fn_arg(0)); 297 298 if (isnan(x)) 299 return ucv_double_new(NAN); 300 301 return ucv_double_new(sinh(x)); 302 } 303 304 /** 305 * Calculates the hyperbolic tangent of `x`. 306 * 307 * On success, this function returns the principal value of the hyperbolic 308 * tangent of `x`; the return value is in the range [-1, 1]. 309 * 310 * The relationship is: tanh = `((e^x) - (e^-x)) / ((e^x) + (e^-x))`, or 311 * tanh = `sinh(x) / cosh(x)`. 312 * 313 * - As `x` decreases below -1, the return value asymptotically expands 314 * toward -1. 315 * - If `x` is 0, 0 is returned. 316 * - As `x` increases above +1, the return value asymptotically expands 317 * toward 1. 318 * 319 * When `x` can't be converted to a numeric value, `NaN` is 320 * returned. 321 * 322 * @function module:math#tanh 323 * 324 * @param {double} x 325 * The `x` value. 326 * 327 * @returns {double} 328 * @example 329 * atan(-100); // -1.0 330 * atan(-10); // -0.99999999587769 331 * atan(0); // 0.0 332 * atan(10); // 0.99999999587769 333 * atan(100); // 1.0 334 */ 335 static uc_value_t * 336 uc_tanh(uc_vm_t *vm, size_t nargs) 337 { 338 double x = ucv_to_double(uc_fn_arg(0)); 339 340 if (isnan(x)) 341 return ucv_double_new(NAN); 342 343 return ucv_double_new(tanh(x)); 344 } 345 346 /** 347 * Calculates the principal value of the arc tangent of `y`/`x`, 348 * using the signs of the two arguments to determine the quadrant 349 * of the result. 350 * 351 * On success, this function returns the principal value of the arc 352 * tangent of `y`/`x` in radians; the return value is in the range [-pi, pi]. 353 * 354 * - If `y` is +0 (-0) and `x` is less than 0, +pi (-pi) is returned. 355 * - If `y` is +0 (-0) and `x` is greater than 0, +0 (-0) is returned. 356 * - If `y` is less than 0 and `x` is +0 or -0, -pi/2 is returned. 357 * - If `y` is greater than 0 and `x` is +0 or -0, pi/2 is returned. 358 * - If either `x` or `y` is NaN, a NaN is returned. 359 * - If `y` is +0 (-0) and `x` is -0, +pi (-pi) is returned. 360 * - If `y` is +0 (-0) and `x` is +0, +0 (-0) is returned. 361 * - If `y` is a finite value greater (less) than 0, and `x` is negative 362 * infinity, +pi (-pi) is returned. 363 * - If `y` is a finite value greater (less) than 0, and `x` is positive 364 * infinity, +0 (-0) is returned. 365 * - If `y` is positive infinity (negative infinity), and `x` is finite, 366 * pi/2 (-pi/2) is returned. 367 * - If `y` is positive infinity (negative infinity) and `x` is negative 368 * infinity, +3 * pi/4 (-3 * pi/4) is returned. 369 * - If `y` is positive infinity (negative infinity) and `x` is positive 370 * infinity, +pi/4 (-pi/4) is returned. 371 * 372 * When either `x` or `y` can't be converted to a numeric value, `NaN` is 373 * returned. 374 * 375 * @function module:math#atan2 376 * 377 * @param {*} y 378 * The `y` value. 379 * 380 * @param {*} x 381 * The `x` value. 382 * 383 * @returns {number} 384 */ 385 static uc_value_t * 386 uc_atan2(uc_vm_t *vm, size_t nargs) 387 { 388 double d1 = ucv_to_double(uc_fn_arg(0)); 389 double d2 = ucv_to_double(uc_fn_arg(1)); 390 391 if (isnan(d1) || isnan(d2)) 392 return ucv_double_new(NAN); 393 394 return ucv_double_new(atan2(d1, d2)); 395 } 396 397 /** 398 * Calculates the tangent of `x`, the floating-point value representing the 399 * angle in radians. 400 * 401 * On success, this function returns the tangent of `x`. 402 * 403 * The relationship is `tan(x) = sin(x) / cos (x)`. A graph of the tangent has 404 * periodic patterns directly related to ratios of pi, where radian values of 405 * whole multiples of (1, 2, 3, ...) pi are 0, and radian values of half 406 * multiples of pi (1/2, 3/2, 5/2, ...) are +/-Infinity. 407 * 408 * 409 * When `x` can't be converted to a numeric value, `NaN` is 410 * returned. 411 * 412 * @function module:math#tan 413 * 414 * @param {double} x 415 * The `x` value. 416 * 417 * @returns {double} 418 */ 419 static uc_value_t * 420 uc_tan(uc_vm_t *vm, size_t nargs) 421 { 422 double x = ucv_to_double(uc_fn_arg(0)); 423 424 if (isnan(x)) 425 return ucv_double_new(NAN); 426 427 return ucv_double_new(tan(x)); 428 } 429 430 /** 431 * Calculates the cosine of `x`, where `x` is given in radians. 432 * 433 * Returns the resulting cosine value. 434 * 435 * Returns `NaN` if the `x` value can't be converted to a number. 436 * 437 * @function module:math#cos 438 * 439 * @param {number} x 440 * Radians value to calculate cosine for. 441 * 442 * @returns {number} 443 */ 444 static uc_value_t * 445 uc_cos(uc_vm_t *vm, size_t nargs) 446 { 447 double d = ucv_to_double(uc_fn_arg(0)); 448 449 if (isnan(d)) 450 return ucv_double_new(NAN); 451 452 return ucv_double_new(cos(d)); 453 } 454 455 /** 456 * Calculates the value of `e` (the base of natural logarithms) 457 * raised to the power of `x`. 458 * 459 * On success, returns the exponential value of `x`. 460 * 461 * - If `x` is positive infinity, positive infinity is returned. 462 * - If `x` is negative infinity, `+0` is returned. 463 * - If the result underflows, a range error occurs, and zero is returned. 464 * - If the result overflows, a range error occurs, and `Infinity` is returned. 465 * 466 * Returns `NaN` if the `x` value can't be converted to a number. 467 * 468 * @function module:math#exp 469 * 470 * @param {number} x 471 * Power to raise `e` to. 472 * 473 * @returns {number} 474 */ 475 static uc_value_t * 476 uc_exp(uc_vm_t *vm, size_t nargs) 477 { 478 double d = ucv_to_double(uc_fn_arg(0)); 479 480 if (isnan(d)) 481 return ucv_double_new(NAN); 482 483 return ucv_double_new(exp(d)); 484 } 485 486 /** 487 * Calculates the natural logarithm of `x`. 488 * 489 * On success, returns the natural logarithm of `x`. 490 * 491 * - If `x` is `1`, the result is `+0`. 492 * - If `x` is positive infinity, positive infinity is returned. 493 * - If `x` is zero, then a pole error occurs, and the function 494 * returns negative infinity. 495 * - If `x` is negative (including negative infinity), then a domain 496 * error occurs, and `NaN` is returned. 497 * 498 * Returns `NaN` if the `x` value can't be converted to a number. 499 * 500 * @function module:math#log 501 * 502 * @param {number} x 503 * Value to calculate natural logarithm of. 504 * 505 * @returns {number} 506 */ 507 static uc_value_t * 508 uc_log(uc_vm_t *vm, size_t nargs) 509 { 510 double d = ucv_to_double(uc_fn_arg(0)); 511 512 if (isnan(d)) 513 return ucv_double_new(NAN); 514 515 return ucv_double_new(log(d)); 516 } 517 518 /** 519 * Calculate base-10 log of x. 520 * 521 * @function module:math#log10 522 * 523 * @param {double} x number 524 * 525 * @returns {double} 526 * The common (base-10) logarithm of x, or 527 * `NaN` if the given argument could not be converted to a number. 528 * 529 * @example 530 * log10(100); // 2.0 531 * log10(10); // 1.0 532 * log10(5); // 0.69897000433602 533 * log10(1); // 0.0 534 * log10(0); // -1e309 535 */ 536 static uc_value_t * 537 uc_log10(uc_vm_t *vm, size_t nargs) 538 { 539 double x = ucv_to_double(uc_fn_arg(0)); 540 541 if (isnan(x)) 542 return ucv_double_new(NAN); 543 544 return ucv_double_new(log10(x)); 545 } 546 547 /** 548 * Calculate base-2 log of x. 549 * 550 * @function module:math#log2 551 * 552 * @param {double} x number 553 * 554 * @returns {double} 555 * The common (base-2) logarithm of x, or 556 * `NaN` if the given argument could not be converted to a number. 557 * 558 * @example 559 * log2(1024); // 10.0 560 * log2(512); // 9.0 561 * log2(16); // 4.0 562 * log2(4); // 2.0 563 * log2(2); // 1.0 564 * log2(1); // 0.0 565 * log2(0); // -1e309 566 */ 567 static uc_value_t * 568 uc_log2(uc_vm_t *vm, size_t nargs) 569 { 570 double x = ucv_to_double(uc_fn_arg(0)); 571 572 if (isnan(x)) 573 return ucv_double_new(NAN); 574 575 return ucv_double_new(log2(x)); 576 } 577 578 /** 579 * Computes the natural (base e) logarithm of 1 + x. This function is more 580 * precise than the expression {@link module:math#log `log`}(1 + x) if x is 581 * close to zero. 582 * 583 * @function module:math#log1p 584 * 585 * @param {double} x number 586 * 587 * @returns {double} 588 * The natural (base e) logarithm of 1 + x, or 589 * `NaN` if the given argument could not be converted to a number. 590 * 591 * @example 592 * log1p(10); // 2.3978952727984 593 * log1p(1); // 0.69314718055995 594 * log1p(0.1); // 0.095310179804325 595 * log1p(0.001); // 0.00099950033308353 596 * log1p(0); // 0.0 597 */ 598 static uc_value_t * 599 uc_log1p(uc_vm_t *vm, size_t nargs) 600 { 601 double x = ucv_to_double(uc_fn_arg(0)); 602 603 if (isnan(x)) 604 return ucv_double_new(NAN); 605 606 return ucv_double_new(log1p(x)); 607 } 608 609 /** 610 * Computes the e (Euler's number, 2.7182818) raised to the given power x, 611 * minus 1.0. This function is more accurate than the expression 612 * {@link module:math#exp `exp(x)`}-1.0 613 * if x is close to zero. 614 * 615 * @function module:math#expm1 616 * 617 * @param {double} x number 618 * 619 * @returns {double} 620 * The e (Euler's number, 2.7182818) raised to the given power x, minus 1.0, or 621 * `NaN` if the given argument could not be converted to a number. 622 * 623 * @example 624 * expm1(10); // 22025.465794807 625 * expm1(1); // 1.718281828459 626 * expm1(0.1); // 0.10517091807565 627 * expm1(0.001); // 0.0010005001667083 628 * exp(0.001)-1; // 0.0010005001667084 629 * expm1(0.0001); // 0.00010000500016667 630 * exp(0.0001)-1; // 0.00010000500016671 631 * expm1(0.000001); // 1.0000005000002e-06 632 * exp(0.000001)-1; // 1.0000004999622e-06 633 * expm1(0); // 0.0 634 */ 635 static uc_value_t * 636 uc_expm1(uc_vm_t *vm, size_t nargs) 637 { 638 double x = ucv_to_double(uc_fn_arg(0)); 639 640 if (isnan(x)) 641 return ucv_double_new(NAN); 642 643 return ucv_double_new(expm1(x)); 644 } 645 646 /** 647 * Calculates the sine of `x`, where `x` is given in radians. 648 * 649 * Returns the resulting sine value. 650 * 651 * - When `x` is positive or negative infinity, a domain error occurs 652 * and `NaN` is returned. 653 * 654 * Returns `NaN` if the `x` value can't be converted to a number. 655 * 656 * @function module:math#sin 657 * 658 * @param {number} x 659 * Radians value to calculate sine for. 660 * 661 * @returns {number} 662 */ 663 static uc_value_t * 664 uc_sin(uc_vm_t *vm, size_t nargs) 665 { 666 double d = ucv_to_double(uc_fn_arg(0)); 667 668 if (isnan(d)) 669 return ucv_double_new(NAN); 670 671 return ucv_double_new(sin(d)); 672 } 673 674 /** 675 * Calculates the non-negative square root of `x`. 676 * 677 * Returns the resulting square root value. 678 * 679 * - If `x` is `+0` (`-0`) then `+0` (`-0`) is returned. 680 * - If `x` is positive infinity, positive infinity is returned. 681 * - If `x` is less than `-0`, a domain error occurs, and `NaN` is returned. 682 * 683 * Returns `NaN` if the `x` value can't be converted to a number. 684 * 685 * @function module:math#sqrt 686 * 687 * @param {number} x 688 * Value to calculate square root for. 689 * 690 * @returns {number} 691 */ 692 static uc_value_t * 693 uc_sqrt(uc_vm_t *vm, size_t nargs) 694 { 695 double d = ucv_to_double(uc_fn_arg(0)); 696 697 if (isnan(d)) 698 return ucv_double_new(NAN); 699 700 return ucv_double_new(sqrt(d)); 701 } 702 703 /** 704 * Calculates the cube root of `x`. 705 * 706 * Returns the resulting cube root value. 707 * 708 * - If `x` is `+0` (`-0`) then `+0` (`-0`) is returned. 709 * - If `x` is (+/-) infinity, (+/-) infinity is returned. 710 * 711 * Returns `NaN` if the `x` value can't be converted to a number. 712 * 713 * @function module:math#cbrt 714 * 715 * @param {double} x 716 * Value to calculate cube root for. 717 * 718 * @returns {double} 719 * @example 720 * cbrt(27); // 3.0 721 * cbrt(0); // 0.0 722 * cbrt(-27); // -3.0 723 */ 724 static uc_value_t * 725 uc_cbrt(uc_vm_t *vm, size_t nargs) 726 { 727 double x = ucv_to_double(uc_fn_arg(0)); 728 729 if (isnan(x)) 730 return ucv_double_new(NAN); 731 732 return ucv_double_new(cbrt(x)); 733 } 734 735 /** 736 * Computes the square root of the sum of the squares of `x` and `y`, i.e. 737 * the hypotenuse without undue overflow or underflow at intermediate stages of 738 * the computation. 739 * 740 * Returns the result of `sqrt(x^2 + y^2)`. 741 * 742 * - If `x` and `y` are `+0` (`-0`) then `+0` (`-0`) is returned. 743 * - If `x` or `y` is `+0` (`-0`) then `+y` or `+x` is returned. 744 * - If `x` or `y` is (+/-) infinity, (+/-) infinity is returned. 745 * 746 * Returns `NaN` if the `x` or `y` value can't be converted to a number. 747 * 748 * @function module:math#hypot 749 * 750 * @param {double} x base 751 * @param {double} y height 752 * 753 * @returns {double} 754 * @example 755 * hypot(3, 3); // 4.2426406871193 756 * hypot(2, 2); // 2.8284271247462 757 * hypot(1, 1); // 1.4142135623731 758 * hypot(0, 0); // 0.0 759 * hypot(-1, -1); // -1.4142135623731 760 */ 761 static uc_value_t * 762 uc_hypot(uc_vm_t *vm, size_t nargs) 763 { 764 double x = ucv_to_double(uc_fn_arg(0)); 765 double y = ucv_to_double(uc_fn_arg(1)); 766 767 if (isnan(x) || isnan(y)) 768 return ucv_double_new(NAN); 769 770 return ucv_double_new(hypot(x, y)); 771 } 772 773 /** 774 * Calculates the value of `x` raised to the power of `y`. 775 * 776 * On success, returns the value of `x` raised to the power of `y`. 777 * 778 * - If the result overflows, a range error occurs, and the function 779 * returns `Infinity`. 780 * - If result underflows, and is not representable, a range error 781 * occurs, and `0.0` with the appropriate sign is returned. 782 * - If `x` is `+0` or `-0`, and `y` is an odd integer less than `0`, 783 * a pole error occurs `Infinity` is returned, with the same sign 784 * as `x`. 785 * - If `x` is `+0` or `-0`, and `y` is less than `0` and not an odd 786 * integer, a pole error occurs and `Infinity` is returned. 787 * - If `x` is `+0` (`-0`), and `y` is an odd integer greater than `0`, 788 * the result is `+0` (`-0`). 789 * - If `x` is `0`, and `y` greater than `0` and not an odd integer, 790 * the result is `+0`. 791 * - If `x` is `-1`, and `y` is positive infinity or negative infinity, 792 * the result is `1.0`. 793 * - If `x` is `+1`, the result is `1.0` (even if `y` is `NaN`). 794 * - If `y` is `0`, the result is `1.0` (even if `x` is `NaN`). 795 * - If `x` is a finite value less than `0`, and `y` is a finite 796 * non-integer, a domain error occurs, and `NaN` is returned. 797 * - If the absolute value of `x` is less than `1`, and `y` is negative 798 * infinity, the result is positive infinity. 799 * - If the absolute value of `x` is greater than `1`, and `y` is 800 * negative infinity, the result is `+0`. 801 * - If the absolute value of `x` is less than `1`, and `y` is positive 802 * infinity, the result is `+0`. 803 * - If the absolute value of `x` is greater than `1`, and `y` is positive 804 * infinity, the result is positive infinity. 805 * - If `x` is negative infinity, and `y` is an odd integer less than `0`, 806 * the result is `-0`. 807 * - If `x` is negative infinity, and `y` less than `0` and not an odd 808 * integer, the result is `+0`. 809 * - If `x` is negative infinity, and `y` is an odd integer greater than 810 * `0`, the result is negative infinity. 811 * - If `x` is negative infinity, and `y` greater than `0` and not an odd 812 * integer, the result is positive infinity. 813 * - If `x` is positive infinity, and `y` less than `0`, the result is `+0`. 814 * - If `x` is positive infinity, and `y` greater than `0`, the result is 815 * positive infinity. 816 * 817 * Returns `NaN` if either the `x` or `y` value can't be converted to a number. 818 * 819 * @function module:math#pow 820 * 821 * @param {number} x 822 * The base value. 823 * 824 * @param {number} y 825 * The power value. 826 * 827 * @returns {number} 828 */ 829 static uc_value_t * 830 uc_pow(uc_vm_t *vm, size_t nargs) 831 { 832 double x = ucv_to_double(uc_fn_arg(0)); 833 double y = ucv_to_double(uc_fn_arg(1)); 834 835 if (isnan(x) || isnan(y)) 836 return ucv_double_new(NAN); 837 838 return ucv_double_new(pow(x, y)); 839 } 840 841 /** 842 * Depending on the arguments, it produces a pseudo-random positive integer, 843 * or a pseudo-random number in a supplied range. 844 * 845 * Without arguments it returns the calculated pseuo-random value. The value 846 * is within the range `0` to `RAND_MAX` inclusive where `RAND_MAX` is a platform 847 * specific value guaranteed to be at least `32767`. 848 * 849 * With 2 arguments `a, b` it returns a number in the range `a` to `b` inclusive. 850 * With a single argument `a` it returns a number in the range `0` to `a` inclusive. 851 * 852 * The {@link module:math#srand `srand()`} function sets its argument as the 853 * seed for a new sequence of pseudo-random integers to be returned by `rand()`. 854 * These sequences are repeatable by calling {@link module:math#srand `srand()`} 855 * with the same seed value. 856 * 857 * If no seed value is explicitly set by calling 858 * {@link module:math#srand `srand()`} prior to the first call to `rand()`, 859 * the math module will automatically seed the PRNG once, using the current 860 * time of day in milliseconds as seed value. 861 * 862 * @function module:math#rand 863 * 864 * @param {number} [a] 865 * End of the desired range. 866 * 867 * @param {number} [b] 868 * The other end of the desired range. 869 * 870 * @returns {number} 871 */ 872 static uc_value_t * 873 uc_rand(uc_vm_t *vm, size_t nargs) 874 { 875 struct timeval tv; 876 877 if (!ucv_boolean_get(uc_vm_registry_get(vm, "math.srand_called"))) { 878 gettimeofday(&tv, NULL); 879 srand((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); 880 881 uc_vm_registry_set(vm, "math.srand_called", ucv_boolean_new(true)); 882 } 883 884 if (nargs == 0) 885 return ucv_int64_new(rand()); 886 887 double a = ucv_to_double(uc_fn_arg(0)), b = 0; 888 889 if (nargs > 1) 890 b = ucv_to_double(uc_fn_arg(1)); 891 892 return ucv_double_new(a + ((b - a) * rand()) / RAND_MAX); 893 } 894 895 /** 896 * Seeds the pseudo-random number generator. 897 * 898 * This functions seeds the PRNG with the given value and thus affects the 899 * pseudo-random integer sequence produced by subsequent calls to 900 * {@link module:math#rand `rand()`}. 901 * 902 * Setting the same seed value will result in the same pseudo-random numbers 903 * produced by {@link module:math#rand `rand()`}. 904 * 905 * @function module:math#srand 906 * 907 * @param {number} seed 908 * The seed value. 909 */ 910 static uc_value_t * 911 uc_srand(uc_vm_t *vm, size_t nargs) 912 { 913 int64_t n = ucv_to_integer(uc_fn_arg(0)); 914 915 srand((unsigned int)n); 916 uc_vm_registry_set(vm, "math.srand_called", ucv_boolean_new(true)); 917 918 return NULL; 919 } 920 921 /** 922 * Tests whether `x` is a `NaN` double. 923 * 924 * This functions checks whether the given argument is of type `double` with 925 * a `NaN` (not a number) value. 926 * 927 * Returns `true` if the value is `NaN`, otherwise false. 928 * 929 * Note that a value can also be checked for `NaN` with the expression 930 * `x !== x` which only evaluates to `true` if `x` is `NaN`. 931 * 932 * @function module:math#isnan 933 * 934 * @param {number} x 935 * The value to test. 936 * 937 * @returns {boolean} 938 */ 939 static uc_value_t * 940 uc_isnan(uc_vm_t *vm, size_t nargs) 941 { 942 uc_value_t *v = uc_fn_arg(0); 943 944 return ucv_boolean_new(ucv_type(v) == UC_DOUBLE && isnan(ucv_double_get(v))); 945 } 946 947 /** 948 * Tests whether `x` is double precision `Infinity`. 949 * 950 * This functions checks whether the given argument is of type `double` of 951 * `Infinity` value. Double precision values >= 1.8e308 are considered `Infinity`. 952 * 953 * Returns `true` if the value is `Infinity`, otherwise false. 954 * 955 * @function module:math#isinf 956 * 957 * @param {number} x 958 * The value to test. 959 * 960 * @returns {boolean} 961 */ 962 static uc_value_t * 963 uc_isinf(uc_vm_t *vm, size_t nargs) 964 { 965 uc_value_t *v = uc_fn_arg(0); 966 967 return ucv_boolean_new(ucv_type(v) == UC_DOUBLE && isinf(ucv_double_get(v))); 968 } 969 970 /** 971 * Returns the radian value of the given degree value. 972 * 973 * @function module:math#deg2rad 974 * 975 * @param {double} number 976 * The number to return the radian value for. 977 * 978 * @returns {number} 979 * Returns the absolute value or `NaN` if the given argument could 980 * not be converted to a number. 981 * @example 982 * deg2rad(180); // 3.1415926535898 983 * deg2rad("180"); // 3.1415926535898 984 */ 985 static uc_value_t * 986 uc_deg2rad(uc_vm_t *vm, size_t nargs) 987 { 988 double d = ucv_to_double(uc_fn_arg(0)); 989 990 return ucv_double_new(degToRad(d)); 991 } 992 993 /** 994 * Returns the degree value of the given radian value. 995 * 996 * @function module:math#rad2deg 997 * 998 * @param {double} number 999 * The number to return the degree value for. 1000 * 1001 * @returns {number} 1002 * Returns the absolute value or `NaN` if the given argument could 1003 * not be converted to a number. 1004 * @example 1005 * rad2deg(3.1415926535898); // 180.0 1006 * rad2deg("3.1415926535898"); // 180.0 1007 */ 1008 static uc_value_t * 1009 uc_rad2deg(uc_vm_t *vm, size_t nargs) 1010 { 1011 double d = ucv_to_double(uc_fn_arg(0)); 1012 1013 return ucv_double_new(radToDeg(d)); 1014 } 1015 1016 /** 1017 * Returns the lesser of two values x and y. 1018 * 1019 * @function module:math#fmin 1020 * 1021 * @param {double} x first parameter 1022 * @param {double} y second parameter 1023 * 1024 * @returns {double} 1025 * Returns the lesser of the two values x or y or `NaN` if a given argument 1026 * could not be converted to a number. Use `(-)Infinity` or `NAN` for 1027 * comparisons involving said values. 1028 * @example 1029 * fmin("180", "-180"); // -180.0 1030 * fmin(180, -180); // -180.0 1031 * fmin(-Infinity, 0); // -1e309 i.e. -infinity in double type representation. 1032 */ 1033 static uc_value_t * 1034 uc_fmin(uc_vm_t *vm, size_t nargs) 1035 { 1036 double x = ucv_to_double(uc_fn_arg(0)); 1037 double y = ucv_to_double(uc_fn_arg(1)); 1038 1039 if (isnan(x) || isnan(y)) 1040 return ucv_double_new(NAN); 1041 1042 return ucv_double_new(fmin(x, y)); 1043 } 1044 1045 /** 1046 * Returns the greater of two values x and y. 1047 * 1048 * @function module:math#fmax 1049 * 1050 * @param {double} x first parameter 1051 * @param {double} y second parameter 1052 * 1053 * @returns {double} 1054 * Returns the greater of the two values x or y or `NaN` if a given argument 1055 * could not be converted to a number. Use `(-)Infinity` or `NAN` for 1056 * comparisons involving said values. 1057 * @example 1058 * fmax("180", "-180"); // 180.0 1059 * fmax(180, -180); // 180.0 1060 * fmax(Infinity, 0); // 1e309 i.e. infinity in double type representation. 1061 */ 1062 static uc_value_t * 1063 uc_fmax(uc_vm_t *vm, size_t nargs) 1064 { 1065 double x = ucv_to_double(uc_fn_arg(0)); 1066 double y = ucv_to_double(uc_fn_arg(1)); 1067 1068 if (isnan(x) || isnan(y)) 1069 return ucv_double_new(NAN); 1070 1071 return ucv_double_new(fmax(x, y)); 1072 } 1073 1074 /** 1075 * Clamps `x` to within `upper` and `lower` bounds if `x` exceeds them. 1076 * 1077 * The operation is effectively: `min(upper, max(x, lower))`. 1078 * 1079 * @function module:math#clamp 1080 * 1081 * @param {double} x number to clamp 1082 * @param {double} upper upper bound 1083 * @param {double} lower lower bound 1084 * 1085 * @returns {double} 1086 * Returns `x` if within `upper` and `lower`, otherwise one of `lower` or `upper` 1087 * if `x` exceeds those bounds, or `NaN` if any given argument 1088 * could not be converted to a number. 1089 * @example 1090 * clamp(1000, 200, 180); // 200.0 1091 * clamp(-1000, 200, 180); // 180.0 1092 * clamp(190, 200, 180); // 190.0 1093 */ 1094 static uc_value_t * 1095 uc_clamp(uc_vm_t *vm, size_t nargs) 1096 { 1097 double x = ucv_to_double(uc_fn_arg(0)); 1098 double upper = ucv_to_double(uc_fn_arg(1)); 1099 double lower = ucv_to_double(uc_fn_arg(2)); 1100 1101 if (isnan(x) || isnan(upper) || isnan(lower)) 1102 return ucv_double_new(NAN); 1103 1104 return ucv_double_new(fmin(upper, fmax(x, lower))); 1105 } 1106 1107 /** 1108 * Returns -1 or 1 depending on the sign of the given number, or 0 if the given 1109 * number itself is zero. 1110 * 1111 * @function module:math#sign 1112 * 1113 * @param {double} x number 1114 * 1115 * @returns {integer} 1116 * Returns -1 or 1 for negative and positive inputs respectively, 0 if the given 1117 * number is zero, or `NaN` if the given argument could not be converted to a 1118 * number. 1119 * @example 1120 * sign(2); // 1 1121 * sign(-8); // -1 1122 * sign(0); // 0 1123 * sign(-0); // 0 1124 */ 1125 static uc_value_t * 1126 uc_sign(uc_vm_t *vm, size_t nargs) 1127 { 1128 double x = ucv_to_double(uc_fn_arg(0)); 1129 1130 if (isnan(x)) 1131 return ucv_double_new(NAN); 1132 1133 return ucv_int64_new((x > 0) - (x < 0)); 1134 } 1135 1136 /** 1137 * Returns -1 or 1 depending on the sign of the given number, or 0 if the given 1138 * number itself is zero. IEEE-754 behaviour. 1139 * 1140 * @function module:math#signbit 1141 * 1142 * @param {double} x number 1143 * 1144 * @returns {integer} 1145 * Returns -1 or 1 for negative and positive inputs respectively, 0 if the given 1146 * number is zero, -1 for -0.0, or `NaN` if the given argument could not be 1147 * converted to a number. 1148 * @example 1149 * signbit(2); // 1 1150 * signbit(-8); // -1 1151 * signbit(0); // 0 1152 * signbit(-0.0); // -1 1153 * signbit(-0); // 0 1154 */ 1155 static uc_value_t * 1156 uc_signbit(uc_vm_t *vm, size_t nargs) 1157 { 1158 double x = ucv_to_double(uc_fn_arg(0)); 1159 1160 if (isnan(x)) 1161 return ucv_double_new(NAN); 1162 1163 return ucv_int64_new(signbit(x) ? -1 : (x > 0)); 1164 } 1165 1166 /** 1167 * Returns -1 or 1 depending on the sign of the given number only (no zero). 1168 * (-)Zero effectively becomes 1. 1169 * 1170 * @function module:math#signnz 1171 * 1172 * @param {double} x number 1173 * 1174 * @returns {integer} 1175 * Returns -1 or +1 for negative and positive inputs respectively, and zero is 1176 * converted to +1, or `NaN` if the given argument could not be converted to a 1177 * number. 1178 * @example 1179 * signnz(2); // 1 1180 * signnz(-8); // -1 1181 * signnz(0); // 1 1182 * signnz(-0); // 1 1183 */ 1184 static uc_value_t * 1185 uc_signnz(uc_vm_t *vm, size_t nargs) 1186 { 1187 double x = ucv_to_double(uc_fn_arg(0)); 1188 1189 if (isnan(x)) 1190 return ucv_double_new(NAN); 1191 1192 return ucv_int64_new((x >= 0) ? 1 : -1); 1193 } 1194 1195 /** 1196 * Returns a double whose magnitude is that of `x`, but whose sign is that of 1197 * `y`. 1198 * 1199 * @function module:math#copysign 1200 * 1201 * @param {double} x number 1202 * @param {double} y number 1203 * 1204 * @returns {double} 1205 * Returns `NaN` if a given argument could not be converted to a number. 1206 * @example 1207 * copysign(-3, -5); // -3.0 1208 * copysign(8, -5); // -8.0 1209 * copysign(-0, 3); // 0.0 1210 */ 1211 static uc_value_t * 1212 uc_copysign(uc_vm_t *vm, size_t nargs) 1213 { 1214 double x = ucv_to_double(uc_fn_arg(0)); 1215 double y = ucv_to_double(uc_fn_arg(1)); 1216 1217 if (isnan(x) || isnan(y)) 1218 return ucv_double_new(NAN); 1219 1220 return ucv_double_new(copysign(x, y)); 1221 } 1222 1223 /** 1224 * Floors `x` to the largest integer value not greater than `x`. 1225 * 1226 * @function module:math#floor 1227 * 1228 * @param {double} x number 1229 * @param {boolean} output_type - false is `integer`, true is `double`. 1230 * 1231 * @returns {number} 1232 * Returns the largest integer value not greater than `x`, or `NaN` if the given 1233 * argument could not be converted to a number. 1234 * @example 1235 * floor(2.7); // 2 1236 * floor(2.7, true); // 2.0 1237 * floor(-2.7); // -3 1238 * floor(-0.0); // 0 1239 * floor(-0.0, true); // -0.0 1240 * floor(-Infinity); // -1e309 i.e. -infinity in double type representation. 1241 */ 1242 static uc_value_t * 1243 uc_floor(uc_vm_t *vm, size_t nargs) 1244 { 1245 double x = ucv_to_double(uc_fn_arg(0)); 1246 bool ot = ucv_boolean_get(uc_fn_arg(1)); 1247 1248 if (isnan(x)) 1249 return ucv_double_new(NAN); 1250 1251 return ot ? ucv_double_new(floor(x)) : ucv_int64_new(floor(x)); 1252 } 1253 1254 /** 1255 * Computes the smallest integer value not less than `x`. 1256 * 1257 * @function module:math#ceil 1258 * 1259 * @param {double} x number 1260 * @param {boolean} output_type - false is `integer`, true is `double`. 1261 * 1262 * @returns {number} 1263 * Returns the smallest integer value not less than `x`, or `NaN` if the given 1264 * argument could not be converted to a number. 1265 * @example 1266 * ceil(2.7); // 3 1267 * ceil(2.7, true); // 3.0 1268 * ceil(-2.7); // -2 1269 * ceil(-0.0); // 0 1270 * ceil(-0.0, true); // -0.0 1271 * ceil(-Infinity); // -1e309 i.e. -infinity in double type representation. 1272 */ 1273 static uc_value_t * 1274 uc_ceil(uc_vm_t *vm, size_t nargs) 1275 { 1276 double x = ucv_to_double(uc_fn_arg(0)); 1277 bool ot = ucv_boolean_get(uc_fn_arg(1)); 1278 1279 if (isnan(x)) 1280 return ucv_double_new(NAN); 1281 1282 return ot ? ucv_double_new(ceil(x)) : ucv_int64_new(ceil(x)); 1283 } 1284 1285 /** 1286 * Returns the integral value nearest to x rounding half-way cases away 1287 * from zero, regardless of the current rounding direction. 1288 * 1289 * @function module:math#round 1290 * 1291 * @param {double} x number 1292 * @param {boolean} output_type - false is `integer`, true is `double`. 1293 * 1294 * @returns {number} 1295 * Returns the rounded integer value of `x`, or `NaN` if the given 1296 * argument could not be converted to a number. 1297 * 1298 * @example 1299 * round(2.4); // 2 1300 * round(2.5); // 3 1301 * round(2.7); // 3 1302 * round(2.7, true); // 3.0 1303 * round(-2.4); // -2 1304 * round(-2.5); // -3 1305 * round(-2.7); // -3 1306 * round(-0.0); // 0 1307 * round(-0.0, true); // -0.0 1308 * round(-Infinity); // -1e309 i.e. -infinity in double type representation. 1309 */ 1310 static uc_value_t * 1311 uc_round(uc_vm_t *vm, size_t nargs) 1312 { 1313 double x = ucv_to_double(uc_fn_arg(0)); 1314 bool ot = ucv_boolean_get(uc_fn_arg(1)); 1315 1316 if (isnan(x)) 1317 return ucv_double_new(NAN); 1318 1319 return ot ? ucv_double_new(round(x)) : ucv_int64_new(round(x)); 1320 } 1321 1322 /** 1323 * Truncate away the decimal portion to produce the nearest integer not greater 1324 * in magnitude than x. 1325 * 1326 * @function module:math#trunc 1327 * 1328 * @param {number} x number 1329 * @param {boolean} output_type - false is `integer`, true is `double`. 1330 * 1331 * @returns {number} 1332 * The integral portion remaining after the decimal portion is truncated, or 1333 * `NaN` if the given argument could not be converted to a number. 1334 * 1335 * @example 1336 * trunc(2.4); // 2 1337 * trunc(2.5); // 2 1338 * trunc(2.7); // 2 1339 * trunc(2.7, true); // 2.0 1340 * trunc(-2.4); // -2 1341 * trunc(-2.5); // -2 1342 * trunc(-2.7); // -2 1343 * trunc(-0.0); // 0 1344 * trunc(-0.0, true); // -0.0 1345 */ 1346 static uc_value_t * 1347 uc_trunc(uc_vm_t *vm, size_t nargs) 1348 { 1349 double x = ucv_to_double(uc_fn_arg(0)); 1350 bool ot = ucv_boolean_get(uc_fn_arg(1)); 1351 1352 if (isnan(x)) 1353 return ucv_double_new(NAN); 1354 1355 return ot ? ucv_double_new(trunc(x)) : ucv_int64_new(trunc(x)); 1356 } 1357 1358 static const uc_function_list_t math_fns[] = { 1359 { "abs", uc_abs }, 1360 { "acos", uc_arccos }, 1361 { "asin", uc_arcsin }, 1362 { "atan", uc_arctan }, 1363 { "atan2", uc_atan2 }, 1364 { "cosh", uc_cosh }, 1365 { "sinh", uc_sinh }, 1366 { "tanh", uc_tanh }, 1367 { "tan", uc_tan }, 1368 { "cos", uc_cos }, 1369 { "exp", uc_exp }, 1370 { "expm1", uc_expm1 }, 1371 { "log", uc_log }, 1372 { "log1p", uc_log1p }, 1373 { "log10", uc_log10 }, 1374 { "log2", uc_log2 }, 1375 { "sin", uc_sin }, 1376 { "sqrt", uc_sqrt }, 1377 { "hypot", uc_hypot }, 1378 { "cbrt", uc_cbrt }, 1379 { "pow", uc_pow }, 1380 { "rand", uc_rand }, 1381 { "srand", uc_srand }, 1382 { "isnan", uc_isnan }, 1383 { "isinf", uc_isinf }, 1384 { "deg2rad", uc_deg2rad }, 1385 { "rad2deg", uc_rad2deg }, 1386 { "fmin", uc_fmin }, 1387 { "fmax", uc_fmax }, 1388 { "clamp", uc_clamp }, 1389 { "sign", uc_sign }, 1390 { "signbit", uc_signbit }, 1391 { "signnz", uc_signnz }, 1392 { "copysign", uc_copysign }, 1393 { "floor", uc_floor }, 1394 { "ceil", uc_ceil }, 1395 { "round", uc_round }, 1396 { "trunc", uc_trunc }, 1397 }; 1398 1399 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 1400 { 1401 uc_function_list_register(scope, math_fns); 1402 1403 uc_vm_registry_set(vm, "math.srand_called", ucv_boolean_new(false)); 1404 } 1405
This page was automatically generated by LXR 0.3.1. • OpenWrt