hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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 };