trig.ha (23963B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 // Sections of the code below are based on Go's implementation, which is, in 5 // turn, based on: 6 // * the Cephes Mathematical Library (cephes/cmath/{sin,..}), available from 7 // http://www.netlib.org/cephes/cmath.tgz. 8 // * FreeBSD's /usr/src/lib/msun/src/{s_asinh.c,...} 9 // The original C code, as well as the respective comments and constants are 10 // from these libraries. 11 // 12 // The Cephes copyright notice: 13 // ==================================================== 14 // Cephes Math Library Release 2.8: June, 2000 15 // Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier 16 // 17 // The readme file at http://netlib.sandia.gov/cephes/ says: 18 // Some software in this archive may be from the book _Methods and 19 // Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster 20 // International, 1989) or from the Cephes Mathematical Library, a 21 // commercial product. In either event, it is copyrighted by the author. 22 // What you see here may be used freely but it comes with no support or 23 // guarantee. 24 // 25 // The two known misprints in the book are repaired here in the 26 // source listings for the gamma function and the incomplete beta 27 // integral. 28 // 29 // Stephen L. Moshier 30 // moshier@na-net.ornl.gov 31 // ==================================================== 32 // 33 // The FreeBSD copyright notice: 34 // ==================================================== 35 // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 36 // 37 // Developed at SunPro, a Sun Microsystems, Inc. business. 38 // Permission to use, copy, modify, and distribute this 39 // software is freely granted, provided that this notice 40 // is preserved. 41 // ==================================================== 42 // 43 // The Go copyright notice: 44 // ==================================================== 45 // Copyright (c) 2009 The Go Authors. All rights reserved. 46 // 47 // Redistribution and use in source and binary forms, with or without 48 // modification, are permitted provided that the following conditions are 49 // met: 50 // 51 // * Redistributions of source code must retain the above copyright 52 // notice, this list of conditions and the following disclaimer. 53 // * Redistributions in binary form must reproduce the above 54 // copyright notice, this list of conditions and the following disclaimer 55 // in the documentation and/or other materials provided with the 56 // distribution. 57 // * Neither the name of Google Inc. nor the names of its 58 // contributors may be used to endorse or promote products derived from 59 // this software without specific prior written permission. 60 // 61 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 62 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 63 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 64 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 65 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 66 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 67 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 68 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 69 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 70 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 71 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 72 // ==================================================== 73 74 // sin coefficients 75 const SIN_CF: [_]f64 = [ 76 1.58962301576546568060e-10, // 0x3de5d8fd1fd19ccd 77 -2.50507477628578072866e-8, // 0xbe5ae5e5a9291f5d 78 2.75573136213857245213e-6, // 0x3ec71de3567d48a1 79 -1.98412698295895385996e-4, // 0xbf2a01a019bfdf03 80 8.33333333332211858878e-3, // 0x3f8111111110f7d0 81 -1.66666666666666307295e-1, // 0xbfc5555555555548 82 ]; 83 84 // cos coefficients 85 const COS_CF: [_]f64 = [ 86 -1.13585365213876817300e-11, // 0xbda8fa49a0861a9b 87 2.08757008419747316778e-9, // 0x3e21ee9d7b4e3f05 88 -2.75573141792967388112e-7, // 0xbe927e4f7eac4bc6 89 2.48015872888517045348e-5, // 0x3efa01a019c844f5 90 -1.38888888888730564116e-3, // 0xbf56c16c16c14f91 91 4.16666666666665929218e-2, // 0x3fa555555555554b 92 ]; 93 94 // PI / 4 split into three parts 95 def PI4A: f64 = 7.85398125648498535156e-1; // 0x3fe921fb40000000 96 def PI4B: f64 = 3.77489470793079817668e-8; // 0x3e64442d00000000 97 def PI4C: f64 = 2.69515142907905952645e-15; // 0x3ce8469898cc5170 98 99 // reduce_threshold is the maximum value of x where the reduction using PI/4 100 // in 3 float64 parts still gives accurate results. This threshold 101 // is set by y*C being representable as a float64 without error 102 // where y is given by y = floor(x * (4 / PI)) and C is the leading partial 103 // terms of 4/PI. Since the leading terms (PI4A and PI4B in sin.go) have 30 104 // and 32 trailing zero bits, y should have less than 30 significant bits. 105 // y < 1<<30 -> floor(x*4/PI) < 1<<30 -> x < (1<<30 - 1) * PI/4 106 // So, conservatively we can take x < 1<<29. 107 // Above this threshold Payne-Hanek range reduction must be used. 108 def REDUCE_THRESHOLD: f64 = ((1u64 << 29): f64); 109 110 // MPI4 is the binary digits of 4/pi as a uint64 array, 111 // that is, 4/pi = Sum MPI4[i]*2^(-64*i) 112 // 19 64-bit digits and the leading one bit give 1217 bits 113 // of precision to handle the largest possible float64 exponent. 114 const MPI4: [_]u64 = [ 115 0x0000000000000001, 116 0x45f306dc9c882a53, 117 0xf84eafa3ea69bb81, 118 0xb6c52b3278872083, 119 0xfca2c757bd778ac3, 120 0x6e48dc74849ba5c0, 121 0x0c925dd413a32439, 122 0xfc3bd63962534e7d, 123 0xd1046bea5d768909, 124 0xd338e04d68befc82, 125 0x7323ac7306a673e9, 126 0x3908bf177bf25076, 127 0x3ff12fffbc0b301f, 128 0xde5e2316b414da3e, 129 0xda6cfd9e4f96136e, 130 0x9e8c7ecd3cbfd45a, 131 0xea4f758fd7cbe2f6, 132 0x7a0e73ef14a525d4, 133 0xd7f6bf623f1aba10, 134 0xac06608df8f6d757, 135 ]; 136 137 // trig_reduce implements Payne-Hanek range reduction by PI/4 for x > 0. It 138 // returns the integer part mod 8 (j) and the fractional part (z) of x / (PI/4). 139 fn trig_reduce(x: f64) (u64, f64) = { 140 // The implementation is based on: "ARGUMENT REDUCTION FOR HUGE 141 // ARGUMENTS: Good to the Last Bit" K. C. Ng et al, March 24, 1992 142 // The simulated multi-precision calculation of x * B uses 64-bit 143 // integer arithmetic. 144 const PI4 = PI / 4f64; 145 if (x < PI4) { 146 return (0u64, x); 147 }; 148 // Extract out the integer and exponent such that x = ix * 2 ** exp 149 let ix = f64bits(x); 150 const exp = 151 ((ix >> F64_MANTISSA_BITS & 152 F64_EXPONENT_MASK): i64) - 153 (F64_EXPONENT_BIAS: i64) - 154 (F64_MANTISSA_BITS: i64); 155 ix = ix & ~(F64_EXPONENT_MASK << F64_MANTISSA_BITS); 156 ix |= 1 << F64_MANTISSA_BITS; 157 // Use the exponent to extract the 3 appropriate uint64 digits from 158 // MPI4, B ~ (z0, z1, z2), such that the product leading digit has the 159 // exponent -61. Note, exp >= -53 since x >= PI4 and exp < 971 for 160 // maximum float64. 161 const digit = ((exp + 61): u64) / 64; 162 const bitshift = ((exp + 61): u64) % 64; 163 const z0 = (MPI4[digit] << bitshift) | 164 (MPI4[digit + 1] >> (64 - bitshift)); 165 const z1 = (MPI4[digit + 1] << bitshift) | 166 (MPI4[digit + 2] >> (64 - bitshift)); 167 const z2 = (MPI4[digit + 2] << bitshift) | 168 (MPI4[digit + 3] >> (64 - bitshift)); 169 // Multiply mantissa by the digits and extract the upper two digits 170 // (hi, lo). 171 const (z2hi, _) = mulu64(z2, ix); 172 const (z1hi, z1lo) = mulu64(z1, ix); 173 const z0lo = z0 * ix; 174 const lo = z1lo + z2hi; 175 let hi = z0lo + z1hi; 176 hi += (z1lo >> 63) & (z2hi >> 63); // carry from lo 177 // The top 3 bits are j. 178 let j = hi >> 61; 179 // Extract the fraction and find its magnitude. 180 hi = hi << 3 | lo >> 61; 181 const lz = ((leading_zeros_u64(hi)): uint); 182 const e = ((F64_EXPONENT_BIAS - (lz + 1)): u64); 183 // Clear implicit mantissa bit and shift into place. 184 hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))); 185 hi >>= 64 - F64_MANTISSA_BITS; 186 // Include the exponent and convert to a float. 187 hi |= e << F64_MANTISSA_BITS; 188 let z = f64frombits(hi); 189 // Map zeros to origin. 190 if (j & 1 == 1) { 191 j += 1; 192 j &= 7; 193 z -= 1f64; 194 }; 195 // Multiply the fractional part by pi/4. 196 return (j, z * PI4); 197 }; 198 199 // cos.c 200 // 201 // Circular cosine 202 // 203 // SYNOPSIS: 204 // 205 // double x, y, cos(); 206 // y = cos( x ); 207 // 208 // DESCRIPTION: 209 // 210 // Range reduction is into intervals of pi/4. The reduction error is nearly 211 // eliminated by contriving an extended precision modular arithmetic. 212 // 213 // Two polynomial approximating functions are employed. 214 // Between 0 and pi/4 the cosine is approximated by 215 // 1 - x**2 Q(x**2). 216 // Between pi/4 and pi/2 the sine is represented as 217 // x + x**3 P(x**2). 218 // 219 // ACCURACY: 220 // 221 // Relative error: 222 // arithmetic domain # trials peak rms 223 // IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17 224 // DEC 0,+1.07e9 17000 3.0e-17 7.2e-18 225 226 // Returns the cosine of x, in radians. 227 export fn cosf64(x: f64) f64 = { 228 if (isnan(x) || isinf(x)) { 229 return NAN; 230 }; 231 232 // Make argument positive 233 let is_negative = false; 234 x = absf64(x); 235 236 let j = 0u64; 237 let y = 0f64; 238 let z = 0f64; 239 if (x >= REDUCE_THRESHOLD) { 240 const reduce_res = trig_reduce(x); 241 j = reduce_res.0; 242 z = reduce_res.1; 243 } else { 244 // Integer part of x/(PI/4), as integer for tests on the phase 245 // angle 246 j = ((x * (4f64 / PI)): i64: u64); 247 // Integer part of x/(PI/4), as float 248 y = (j: i64: f64); 249 250 // Map zeros to origin 251 if (j & 1 == 1) { 252 j += 1; 253 y += 1f64; 254 }; 255 // Octant modulo 2PI radians (360 degrees) 256 j &= 7; 257 // Extended precision modular arithmetic 258 z = ((x - (y * PI4A)) - (y * PI4B)) - (y * PI4C); 259 }; 260 261 if (j > 3) { 262 j -= 4; 263 is_negative = !is_negative; 264 }; 265 if (j > 1) { 266 is_negative = !is_negative; 267 }; 268 269 const zz = z * z; 270 if (j == 1 || j == 2) { 271 y = z + z * zz * ((((((SIN_CF[0] * zz) + 272 SIN_CF[1]) * zz + 273 SIN_CF[2]) * zz + 274 SIN_CF[3]) * zz + 275 SIN_CF[4]) * zz + 276 SIN_CF[5]); 277 } else { 278 y = 1.0 - 0.5 * zz + zz * zz * ((((((COS_CF[0] * zz) + 279 COS_CF[1]) * zz + 280 COS_CF[2]) * zz + 281 COS_CF[3]) * zz + 282 COS_CF[4]) * zz + 283 COS_CF[5]); 284 }; 285 if (is_negative) { 286 y = -y; 287 }; 288 return y; 289 }; 290 291 // sin.c 292 // 293 // Circular sine 294 // 295 // SYNOPSIS: 296 // 297 // double x, y, sin(); 298 // y = sin( x ); 299 // 300 // DESCRIPTION: 301 // 302 // Range reduction is into intervals of pi/4. The reduction error is nearly 303 // eliminated by contriving an extended precision modular arithmetic. 304 // 305 // Two polynomial approximating functions are employed. 306 // Between 0 and pi/4 the sine is approximated by 307 // x + x**3 P(x**2). 308 // Between pi/4 and pi/2 the cosine is represented as 309 // 1 - x**2 Q(x**2). 310 // 311 // ACCURACY: 312 // 313 // Relative error: 314 // arithmetic domain # trials peak rms 315 // DEC 0, 10 150000 3.0e-17 7.8e-18 316 // IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17 317 // 318 // Partial loss of accuracy begins to occur at x = 2**30 = 1.074e9. The loss 319 // is not gradual, but jumps suddenly to about 1 part in 10e7. Results may 320 // be meaningless for x > 2**49 = 5.6e14. 321 322 // Returns the sine of x, in radians. 323 export fn sinf64(x: f64) f64 = { 324 if (x == 0f64 || isnan(x)) { 325 return x; 326 } else if (isinf(x)) { 327 return NAN; 328 }; 329 330 // Make argument positive but save the sign 331 let is_negative = false; 332 if (x < 0f64) { 333 x = -x; 334 is_negative = true; 335 }; 336 337 let j = 0u64; 338 let y = 0f64; 339 let z = 0f64; 340 if (x >= REDUCE_THRESHOLD) { 341 const reduce_res = trig_reduce(x); 342 j = reduce_res.0; 343 z = reduce_res.1; 344 } else { 345 // Integer part of x/(PI/4), as integer for tests on the phase 346 // angle 347 j = ((x * (4f64 / PI)): i64: u64); 348 // Integer part of x/(PI/4), as float 349 y = (j: i64: f64); 350 351 // Map zeros to origin 352 if (j & 1 == 1) { 353 j += 1; 354 y += 1f64; 355 }; 356 // Octant modulo 2PI radians (360 degrees) 357 j &= 7; 358 // Extended precision modular arithmetic 359 z = ((x - (y * PI4A)) - (y * PI4B)) - (y * PI4C); 360 }; 361 362 // Reflect in x axis 363 if (j > 3) { 364 j -= 4; 365 is_negative = !is_negative; 366 }; 367 368 const zz = z * z; 369 if (j == 1 || j == 2) { 370 y = 1.0 - 0.5 * zz + zz * zz * 371 ((((((COS_CF[0] * zz) + 372 COS_CF[1]) * zz + 373 COS_CF[2]) * zz + 374 COS_CF[3]) * zz + 375 COS_CF[4]) * zz + 376 COS_CF[5]); 377 } else { 378 y = z + z * zz * 379 ((((((SIN_CF[0] * zz) + 380 SIN_CF[1]) * zz + 381 SIN_CF[2]) * zz + 382 SIN_CF[3]) * zz + 383 SIN_CF[4]) * zz + 384 SIN_CF[5]); 385 }; 386 if (is_negative) { 387 y = -y; 388 }; 389 return y; 390 }; 391 392 // tan.c 393 // 394 // Circular tangent 395 // 396 // SYNOPSIS: 397 // 398 // double x, y, tan(); 399 // y = tan( x ); 400 // 401 // DESCRIPTION: 402 // 403 // Returns the circular tangent of the radian argument x. 404 // 405 // Range reduction is modulo pi/4. A rational function 406 // x + x**3 P(x**2)/Q(x**2) 407 // is employed in the basic interval [0, pi/4]. 408 // 409 // ACCURACY: 410 // Relative error: 411 // arithmetic domain # trials peak rms 412 // DEC +-1.07e9 44000 4.1e-17 1.0e-17 413 // IEEE +-1.07e9 30000 2.9e-16 8.1e-17 414 // 415 // Partial loss of accuracy begins to occur at x = 2**30 = 1.074e9. The loss 416 // is not gradual, but jumps suddenly to about 1 part in 10e7. Results may 417 // be meaningless for x > 2**49 = 5.6e14. 418 // [Accuracy loss statement from sin.go comments.] 419 420 // tan coefficients 421 const TAN_P: [_]f64 = [ 422 -1.30936939181383777646e4, // 0xc0c992d8d24f3f38 423 1.15351664838587416140e6, // 0x413199eca5fc9ddd 424 -1.79565251976484877988e7, // 0xc1711fead3299176 425 ]; 426 const TAN_Q: [_]f64 = [ 427 1.00000000000000000000e0, 428 1.36812963470692954678e4, // 0x40cab8a5eeb36572 429 -1.32089234440210967447e6, // 0xc13427bc582abc96 430 2.50083801823357915839e7, // 0x4177d98fc2ead8ef 431 -5.38695755929454629881e7, // 0xc189afe03cbe5a31 432 ]; 433 434 // Returns the tangent of x, in radians. 435 export fn tanf64(x: f64) f64 = { 436 if (x == 0f64 || isnan(x)) { 437 return x; 438 } else if (isinf(x)) { 439 return NAN; 440 }; 441 442 // Make argument positive but save the sign 443 let is_negative = false; 444 if (x < 0f64) { 445 x = -x; 446 is_negative = true; 447 }; 448 let j = 0u64; 449 let y = 0f64; 450 let z = 0f64; 451 if (x >= REDUCE_THRESHOLD) { 452 const reduce_res = trig_reduce(x); 453 j = reduce_res.0; 454 z = reduce_res.1; 455 } else { 456 // Integer part of x/(PI/4), as integer for tests on the phase 457 // angle 458 j = ((x * (4f64 / PI)): i64: u64); 459 // Integer part of x/(PI/4), as float 460 y = (j: i64: f64); 461 462 // Map zeros and singularities to origin 463 if (j & 1 == 1) { 464 j += 1; 465 y += 1f64; 466 }; 467 468 z = ((x - (y * PI4A)) - (y * PI4B)) - (y * PI4C); 469 }; 470 const zz = z * z; 471 472 if (zz > 1e-14) { 473 y = z + z * (zz * 474 (((TAN_P[0] * zz) + TAN_P[1]) * zz + TAN_P[2]) / 475 ((((zz + TAN_Q[1]) * zz + 476 TAN_Q[2]) * zz + 477 TAN_Q[3]) * zz + 478 TAN_Q[4])); 479 } else { 480 y = z; 481 }; 482 if (j & 2 == 2) { 483 y = -1f64 / y; 484 }; 485 if (is_negative) { 486 y = -y; 487 }; 488 return y; 489 }; 490 491 // Evaluates a series valid in the range [0, 0.66]. 492 fn xatan(x: f64) f64 = { 493 const P0 = -8.750608600031904122785e-01; 494 const P1 = -1.615753718733365076637e+01; 495 const P2 = -7.500855792314704667340e+01; 496 const P3 = -1.228866684490136173410e+02; 497 const P4 = -6.485021904942025371773e+01; 498 const Q0 = 2.485846490142306297962e+01; 499 const Q1 = 1.650270098316988542046e+02; 500 const Q2 = 4.328810604912902668951e+02; 501 const Q3 = 4.853903996359136964868e+02; 502 const Q4 = 1.945506571482613964425e+02; 503 let z = x * x; 504 z = z * ((((P0 * z + P1) * z + P2) * z + P3) * z + P4) / 505 (((((z + Q0) * z + Q1) * z + Q2) * z + Q3) * z + Q4); 506 z = (x * z) + x; 507 return z; 508 }; 509 510 // Reduces argument (known to be positive) to the range [0, 0.66] and calls 511 // xatan. 512 fn satan(x: f64) f64 = { 513 // pi / 2 = PIO2 + morebits 514 const morebits = 6.123233995736765886130e-17; 515 // tan(3 * pi / 8) 516 const tan3pio8 = 2.41421356237309504880; 517 if (x <= 0.66) { 518 return xatan(x); 519 }; 520 if (x > tan3pio8) { 521 return (PI / 2f64) - xatan(1f64 / x) + morebits; 522 }; 523 return (PI / 4f64) + 524 xatan((x - 1f64) / (x + 1f64)) + 525 (0.5f64 * morebits); 526 }; 527 528 // Returns the arcsine, in radians, of x. 529 export fn asinf64(x: f64) f64 = { 530 if (x == 0f64) { 531 return x; 532 }; 533 let is_negative = false; 534 if (x < 0.064) { 535 x = -x; 536 is_negative = true; 537 }; 538 if (x > 1f64) { 539 return NAN; 540 }; 541 let temp = sqrtf64(1f64 - x * x); 542 if (x > 0.7f64) { 543 temp = PI / 2f64 - satan(temp / x); 544 } else { 545 temp = satan(x / temp); 546 }; 547 548 if (is_negative) { 549 temp = -temp; 550 }; 551 return temp; 552 }; 553 554 // Returns the arccosine, in radians, of x. 555 export fn acosf64(x: f64) f64 = { 556 return PI / 2f64 - asinf64(x); 557 }; 558 559 // atan.c 560 // Inverse circular tangent (arctangent) 561 // 562 // SYNOPSIS: 563 // double x, y, atan(); 564 // y = atan( x ); 565 // 566 // DESCRIPTION: 567 // Returns radian angle between -pi/2 and +pi/2 whose tangent is x. 568 // 569 // Range reduction is from three intervals into the interval from zero to 0.66. 570 // The approximant uses a rational function of degree 4/5 of the form 571 // x + x**3 P(x)/Q(x). 572 // 573 // ACCURACY: 574 // Relative error: 575 // arithmetic domain # trials peak rms 576 // DEC -10, 10 50000 2.4e-17 8.3e-18 577 // IEEE -10, 10 10^6 1.8e-16 5.0e-17 578 579 // Returns the arctangent, in radians, of x. 580 export fn atanf64(x: f64) f64 = { 581 if (x == 0f64) { 582 return x; 583 }; 584 if (x > 0f64) { 585 return satan(x); 586 }; 587 return -satan(-x); 588 }; 589 590 // Floating-point hyperbolic sine and cosine. 591 // The exponential func is called for arguments greater in magnitude than 0.5. 592 // A series is used for arguments smaller in magnitude than 0.5. 593 // Cosh(x) is computed from the exponential func for all arguments. 594 595 // Returns the hyperbolic sine of x. 596 export fn sinhf64(x: f64) f64 = { 597 // The coefficients are #2029 from Hart & Cheney. (20.36D) 598 const P0 = -0.6307673640497716991184787251e+6; 599 const P1 = -0.8991272022039509355398013511e+5; 600 const P2 = -0.2894211355989563807284660366e+4; 601 const P3 = -0.2630563213397497062819489e+2; 602 const Q0 = -0.6307673640497716991212077277e+6; 603 const Q1 = 0.1521517378790019070696485176e+5; 604 const Q2 = -0.173678953558233699533450911e+3; 605 606 let is_negative = false; 607 if (x < 0f64) { 608 x = -x; 609 is_negative = true; 610 }; 611 612 let temp = 0f64; 613 if (x > 21f64) { 614 temp = expf64(x) * 0.5f64; 615 } else if (x > 0.5f64) { 616 const ex = expf64(x); 617 temp = (ex - (1f64 / ex)) * 0.5f64; 618 } else { 619 const sq = x * x; 620 temp = (((P3 * sq + P2) * sq + P1) * sq + P0) * x; 621 temp = temp / (((sq + Q2) * sq + Q1) * sq + Q0); 622 }; 623 624 if (is_negative) { 625 temp = -temp; 626 }; 627 628 return temp; 629 }; 630 631 // Returns the hyperbolic cosine of x. 632 export fn coshf64(x: f64) f64 = { 633 x = absf64(x); 634 if (x > 21f64) { 635 return expf64(x) * 0.5f64; 636 }; 637 const ex = expf64(x); 638 return (ex + 1f64 / ex) * 0.5f64; 639 }; 640 641 // tanh.c 642 // 643 // Hyperbolic tangent 644 // 645 // SYNOPSIS: 646 // 647 // double x, y, tanh(); 648 // 649 // y = tanh( x ); 650 // 651 // DESCRIPTION: 652 // 653 // Returns hyperbolic tangent of argument in the range MINLOG to MAXLOG. 654 // MAXLOG = 8.8029691931113054295988e+01 = log(2**127) 655 // MINLOG = -8.872283911167299960540e+01 = log(2**-128) 656 // 657 // A rational function is used for |x| < 0.625. The form 658 // x + x**3 P(x)/Q(x) of Cody & Waite is employed. 659 // Otherwise, 660 // tanh(x) = sinh(x)/cosh(x) = 1 - 2/(exp(2x) + 1). 661 // 662 // ACCURACY: 663 // 664 // Relative error: 665 // arithmetic domain # trials peak rms 666 // IEEE -2,2 30000 2.5e-16 5.8e-17 667 668 // tanh coefficients 669 const TANH_P: [_]f64 = [ 670 -9.64399179425052238628e-1, 671 -9.92877231001918586564e1, 672 -1.61468768441708447952e3, 673 ]; 674 const TANH_Q: [_]f64 = [ 675 1.12811678491632931402e2, 676 2.23548839060100448583e3, 677 4.84406305325125486048e3, 678 ]; 679 680 // Returns the hyperbolic tangent of x. 681 export fn tanhf64(x: f64) f64 = { 682 const MAXLOG = 8.8029691931113054295988e+01; // log(2**127) 683 let z = absf64(x); 684 if (z > 0.5f64 * MAXLOG) { 685 if (x < 0f64) { 686 return -1f64; 687 }; 688 return 1f64; 689 } else if (z >= 0.625f64) { 690 const s = expf64(2f64 * z); 691 z = 1f64 - 2f64 / (s + 1f64); 692 if (x < 0f64) { 693 z = -z; 694 }; 695 } else { 696 if (x == 0f64) { 697 return x; 698 }; 699 const s = x * x; 700 z = x + x * s * ((TANH_P[0] * s + TANH_P[1]) * s + TANH_P[2]) / 701 (((s + TANH_Q[0]) * s + TANH_Q[1]) * s + TANH_Q[2]); 702 }; 703 return z; 704 }; 705 706 // asinh(x) 707 // Method : 708 // Based on 709 // asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ] 710 // we have 711 // asinh(x) := x if 1+x*x=1, 712 // := sign(x)*(log(x)+ln2)) for large |x|, else 713 // := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else 714 // := sign(x)*log1p(|x| + x**2/(1 + sqrt(1+x**2))) 715 // 716 717 // Returns the inverse hyperbolic sine of x. 718 export fn asinhf64(x: f64) f64 = { 719 const NEAR_ZERO = 1f64 / ((1i64 << 28): f64); 720 const LARGE = ((1i64 << 28): f64); 721 722 if (isnan(x) || isinf(x)) { 723 return x; 724 }; 725 726 let is_negative = false; 727 if (x < 0f64) { 728 x = -x; 729 is_negative = true; 730 }; 731 732 let temp = 0f64; 733 734 if (x > LARGE) { 735 // |x| > 2**28 736 temp = logf64(x) + LN_2; 737 } else if (x > 2f64) { 738 // 2**28 > |x| > 2.0 739 temp = logf64(2f64 * x + 740 1f64 / (sqrtf64(x * x + 1f64) + x)); 741 } else if (x < NEAR_ZERO) { 742 // |x| < 2**-28 743 temp = x; 744 } else { 745 // 2.0 > |x| > 2**-28 746 temp = log1pf64(x + x * x / 747 (1f64 + sqrtf64(1f64 + x * x))); 748 }; 749 if (is_negative) { 750 temp = -temp; 751 }; 752 return temp; 753 }; 754 755 // __ieee754_acosh(x) 756 // Method : 757 // Based on 758 // acosh(x) = log [ x + sqrt(x*x-1) ] 759 // we have 760 // acosh(x) := log(x)+ln2, if x is large; else 761 // acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else 762 // acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1. 763 // 764 // Special cases: 765 // acosh(x) is NaN with signal if x<1. 766 // acosh(NaN) is NaN without signal. 767 // 768 769 // Returns the inverse hyperbolic cosine of x. 770 export fn acoshf64(x: f64) f64 = { 771 const LARGE = ((1i64 << 28): f64); 772 773 if (x < 1f64 || isnan(x)) { 774 return NAN; 775 } else if (x == 1f64) { 776 return 0f64; 777 } else if (x >= LARGE) { 778 // x > 2**28 779 return logf64(x) + LN_2; 780 } else if (x > 2f64) { 781 // 2**28 > x > 2 782 return logf64(2f64 * x - 1f64 / 783 (x + sqrtf64(x * x - 1f64))); 784 }; 785 const t = x - 1f64; 786 // 2 >= x > 1 787 return log1pf64(t + sqrtf64(2f64 * t + t * t)); 788 }; 789 790 // __ieee754_atanh(x) 791 // Method : 792 // 1. Reduce x to positive by atanh(-x) = -atanh(x) 793 // 2. For x>=0.5 794 // 1 2x x 795 // atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------) 796 // 2 1 - x 1 - x 797 // 798 // For x<0.5 799 // atanh(x) = 0.5*log1p(2x+2x*x/(1-x)) 800 // 801 // Special cases: 802 // atanh(x) is NaN if |x| > 1 with signal; 803 // atanh(NaN) is that NaN with no signal; 804 // atanh(+-1) is +-INF with signal. 805 // 806 807 // Returns the inverse hyperbolic tangent of x. 808 export fn atanhf64(x: f64) f64 = { 809 const NEAR_ZERO = 1f64 / ((1i64 << 28): f64); 810 811 if (x < -1f64 || x > 1.064) { 812 return NAN; 813 } else if (isnan(x)) { 814 return NAN; 815 } else if (x == 1f64) { 816 return INF; 817 } else if (x == -1f64) { 818 return -INF; 819 }; 820 821 let is_negative = false; 822 823 if (x < 0f64) { 824 x = -x; 825 is_negative = true; 826 }; 827 828 let temp = 0f64; 829 830 if (x < NEAR_ZERO) { 831 temp = x; 832 } else if (x < 0.5f64) { 833 temp = x + x; 834 temp = 0.5f64 * log1pf64(temp + temp * x / (1f64 - x)); 835 } else { 836 temp = 0.5f64 * log1pf64((x + x) / (1f64 - x)); 837 }; 838 if (is_negative) { 839 temp = -temp; 840 }; 841 return temp; 842 }; 843 844 // Returns the arctangent, in radians, of y / x. 845 export fn atan2f64(y: f64, x: f64) f64 = { 846 if (isnan(y) || isnan(x)) { 847 return NAN; 848 } else if (y == 0f64) { 849 x = if (x >= 0f64 && signf64(x) > 0) 0f64 else PI; 850 return copysignf64(x, y); 851 } else if (x == 0f64) { 852 return copysignf64(PI / 2f64, y); 853 } else if (isinf(x)) { 854 if (signf64(x) > 0) { 855 x = if (isinf(y)) PI / 4f64 else 0f64; 856 return copysignf64(x, y); 857 } else { 858 x = if (isinf(y)) 3f64 * PI / 4f64 else PI; 859 return copysignf64(x, y); 860 }; 861 } else if (isinf(y)) { 862 return copysignf64(PI / 2f64, y); 863 }; 864 865 const q = atanf64(y / x); 866 if (x < 0f64) { 867 return if (q <= 0f64) q + PI else q - PI; 868 }; 869 return q; 870 }; 871 872 // Returns the square root of a*a + b*b, taking care to avoid unnecessary 873 // overflow and underflow. 874 export fn hypotf64(a: f64, b: f64) f64 = { 875 if (isinf(a) || isinf(b)) { 876 return INF; 877 } else if (isnan(a) || isnan(b)) { 878 return NAN; 879 }; 880 a = absf64(a); 881 b = absf64(b); 882 if (a < b) { 883 const temp = a; 884 a = b; 885 b = temp; 886 }; 887 if (a == 0f64) { 888 return 0f64; 889 }; 890 b = b / a; 891 return a * sqrtf64(1f64 + b * b); 892 };