/* Copyright 1996 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* math.c: ANSI draft (X3J11 May 86) library code, section D.5 */ /* Copyright (C) Codemist Ltd, 1988 */ /* version 0.04b */ /* Nov 87: fix bug in ibm frexp(-ve arg). */ /* * This version of the code takes the view that whenever there is an * error a NaN should be handed back (as well as errno getting set). The * value HUGE_VAL is used, which is not actually a NaN but which will * often lead to exponent overflow pretty soon if it is used. ACN is * unclear if this is sensible, and has had a program fall over when * atan2(0.0, 0.0) handed back HUGE_VAL rather than some less vicious * value (e.g. 0.0). He can imagine people who expect pow(0.0, 0.0) to * be 1.0 (or maybe 0.0, but certainly not HUGE_VAL), and who expect * sin(x) to be <= 1.0 in absolute value regardless of anything. Thus * the current state is OK if we are being strict, but mey be unfriendly * in some cases? Thoughts and comments, anybody? */ #include "hostsys.h" #include <limits.h> #include <errno.h> /* This file contains code for most of the math routines from <math.h> */ /* On the ARM some of these routines are implemented as floating point */ /* opcodes and as such appear in startup.s */ #ifndef NO_FLOATING_POINT #include <math.h> /* for forward references */ #ifdef IBMFLOAT const double __huge_val = 7.2370055773322621e+75; #else /* On the ARM, this has moved into the library's static data area */ /* so that it still works with the Shared C Library module. */ /* const double __huge_val = 1.79769313486231571e+308; */ #endif #ifdef IBMFLOAT double frexp(d, lvn) double d; int *lvn; { fp_number d1; int n; if (d==0.0) /* I worry a little about signed zeros here. I hope that -0.0 == 0.0 */ { *lvn = 0; return 0.0; } d1.d = d; n = 4*(d1.i.x - 0x40); /* excess 64 exponent */ d1.i.x = 0x40; d = d1.d; /* Note that the following code works for unnormalised numbers, but */ /* can then take 55 cycles to converge instead of usual 3 max. */ while ((d>=0 ? d : -d) < 0.5) d = d+d, n--; /* Now d is most definitely normalised. */ *lvn = n; return d; } double ldexp(d, n) double d; int n; { fp_number d1; int nx; if (d==0.0) return 0.0; /* special case */ d1.d = d; nx = d1.i.x + (n & ~3)/4; n &= 3; #ifndef DO_NOT_SUPPORT_UNNORMALIZED_NUMBERS /* The following code gets the msd/expt right for unnormalised nos. */ d1.i.x = 0x40; d1.d += 0.0; /* i.e. normalise */ nx += d1.i.x - 0x40; #endif { int mhi = d1.i.mhi; int nx1 = (mhi & 0x00c00000)==0 ? ((mhi & 0x00200000)==0 ? n - 3 : n - 2) : ((mhi & 0x00800000)==0 ? n - 1 : n); if (nx1 > 0) nx++, n -= 4; /* That just dealt with the fact that in IBM format the exponent is for */ /* base 16 and so scaling by a power of two can involve a real multiply. */ /* I now know what the true exponent (nx) in the result will be. */ } if (nx > 0x7f) /* Overflow (maybe do a raise() ?) */ { d1.i.x = 0x7f; d1.i.mhi = 0xffffff; d1.i.mlo = 0xffffffff; return d1.d; } if (nx < 0) /* Deal with underflow/unnormalised */ { if (nx <= -14) return 0.0; d1.i.x = 0; while (nx < 0) d1.d /= 16, nx++; /* de-normalise gracefully */ } d1.i.x = nx; { double d2; switch (n) { case -3:d2 = 0.125; break; case -2:d2 = 0.25; break; case -1:d2 = 0.5; break; default: /* avoid dataflow whinge */ case 0: d2 = 1.0; break; case 1: d2 = 2.0; break; case 2: d2 = 4.0; break; case 3: d2 = 8.0; break; } d1.d *= d2; } return d1.d; } #else /* Here is the IEEE format stuff */ #ifndef DO_NOT_SUPPORT_UNNORMALIZED_NUMBERS double frexp(d, lvn) double d; int *lvn; { /* This version works even if d starts off as an unnormalized number in */ /* the IEEE sense. But in that special case it will be mighty slow! */ /* By that we mean at most 52 iterations for the smallest number. */ fp_number d1; int n; if (d==0.0) { *lvn = 0; return 0.0; } d1.d = d; if ((n = d1.i.x - 0x3fe) == -0x3fe) { int flag; /* Here d1 has zero in its exponent field - this means that the mantissa */ /* is un-normalized. I have to shift it left (at least one bit) until a */ /* suitable nonzero bit appears to go in the implicit-bit place in the */ /* fractional result. For each bit shifted I need to adjust the final */ /* exponent that will be returned. */ /* I have already tested to see if d was zero so the fllowing loop MUST */ /* terminate. */ do { flag = d1.i.mhi & 0x00080000; d1.i.mhi = (d1.i.mhi << 1) | (d1.i.mlo >> 31); d1.i.mlo = d1.i.mlo << 1; n--; } while (flag==0); } *lvn = n; d1.i.x = 0x3fe; return d1.d; } #else /* DO_NOT_SUPPORT_UNNORMALIZED_NUMBERS */ double frexp(d, lvn) double d; int *lvn; { fp_number d1; if (d==0.0) { *lvn = 0; return 0.0; } d1.d = d; *lvn = d1.i.x - 0x3fe; d1.i.x = 0x3fe; return d1.d; } #endif /* DO_NOT_SUPPORT_UNNORMALIZED_NUMBERS */ double ldexp(d, n) double d; int n; { fp_number d1; int nx; if (d==0.0) return 0.0; /* special case */ d1.d = d; nx = (int) d1.i.x + n; if (nx >= 0x7ff) { errno = ERANGE; return HUGE_VAL; /* overflow yields 'infinity' */ } /* Maybe I should be prepared to generate un-normalized numbers here, or */ /* even deal with input d un-normalized and n positive yielding a proper */ /* result. All that seems like a lot of work and so I will not even try */ /* in this version of the code! */ else if (nx <= 0) return 0.0; /* deal with underflow */ d1.i.x = nx; return (d1.d); } #endif #ifdef IBMFLOAT #define _exp_arg_limit 174.673089501106208 #else #define _exp_arg_limit 709.78271289338397 #endif /* machine independent code - but beware the 1e-20's */ #define _pi_ 3.14159265358979323846 #define _pi_3 1.04719755119659774615 #define _pi_2 1.57079632679489661923 #define _pi_4 0.78539816339744830962 #define _pi_6 0.52359877559829887038 #define _sqrt_half 0.70710678118654752440 #ifndef HOST_HAS_TRIG /* The ARM has a load of trig functions etc available as opcodes, so */ /* has no need for these software versions shown here. */ #undef sin #undef cos #undef atan static double _sincos(double x, double y, int sign, int coscase) { int n; double xn, f, g, r; if (y >= 1.0e9) /* fail if argument is overlarge */ { errno = EDOM; return -HUGE_VAL; } n = (int) ((y + _pi_2) / _pi_); xn = (double) n; if ((n & 1) != 0) sign = -sign; if (coscase) xn = xn - 0.5; /* Note that these days C is REQUIRED to observe the brackets used here. */ /* The compiler is NOT allowed to re-associate the additions. */ #ifdef IBMFLOAT { double x1 = (double)(int)x; /* observe that the range check on y assures me that (int)x is OK. */ double x2 = x - x1; f = ((x1 - xn*3.1416015625) + x2) + xn*8.908910206761537356617e-6; } #else f = (x - xn*3.1416015625) + xn*8.908910206761537356617e-6; #endif /* I expect that the absolute value of f is less than pi/2 here */ if (fabs(f) >= 1.e-10) #define _sincos_r1 -0.16666666666666665052 #define _sincos_r2 0.83333333333331650315e-2 #define _sincos_r3 -0.19841269841201840457e-3 #define _sincos_r4 0.27557319210152756119e-5 #define _sincos_r5 -0.25052106798274584544e-7 #define _sincos_r6 0.16058936490371589114e-9 #define _sincos_r7 -0.76429178068910467734e-12 #define _sincos_r8 0.27204790957888846175e-14 { g = f*f; r = ((((((((_sincos_r8) * g + _sincos_r7) * g + _sincos_r6) * g + _sincos_r5) * g + _sincos_r4) * g + _sincos_r3) * g + _sincos_r2) * g + _sincos_r1) * g; f += f*r; }; if (sign < 0) return -f; else return f; } double sin(double x) { if (x < 0.0) return _sincos(-x, -x, -1, 0); else return _sincos(x, x, 1, 0); } double cos(double x) { if (x < 0.0) return _sincos(-x, _pi_2 - x, 1, 1); else return _sincos(x, _pi_2 + x, 1, 1); } #ifdef IBMFLOAT #define _exp_negative_arg_limit -180.218266945585778 #else /* NB: the following value is a proper limit provided denormalised */ /* values are not being supported. It would need to be changed if they */ /* were to start existing. */ #define _exp_negative_arg_limit -708.39641853226408 #endif double exp(double x) { int n; double xn, g, z, gp, q, r; if (x > _exp_arg_limit) { errno = ERANGE; return HUGE_VAL; } if (x < _exp_negative_arg_limit) return 0.0; if (fabs(x) < 1.e-20) return 1.0; /* In C the cast (int)x truncates towards zero. Here I want to round. */ n = (int)((x >= 0 ? 0.5 : -0.5) + 1.44266950408889634074 * x); xn = (double)n; #ifdef IBMFLOAT { double x1 = (double)(int)x; double x2 = x - x1; g = ((x1 - xn * 0.693359375) + x2) - xn * (-2.1219444005469058277e-4); } #else g = (x - xn * 0.693359375) - xn * (-2.1219444005469058277e-4); #endif z = g * g; #define _exp_p0 0.249999999999999993 #define _exp_p1 0.694360001511792852e-2 #define _exp_p2 0.165203300268279130e-4 #define _exp_q0 0.500000000000000000 #define _exp_q1 0.555538666969001188e-1 #define _exp_q2 0.495862884905441294e-3 gp = ((_exp_p2 * z + _exp_p1) * z + _exp_p0) * g; q = (_exp_q2 * z + _exp_q1) * z + _exp_q0; r = 0.5 + gp / (q - gp); return ldexp(r, n + 1); } double log(double x) { double f, znum, zden, z, w, r, xn; int n; if (x <= 0.0) { if (x==0.0) { errno = ERANGE; return -HUGE_VAL; } else { errno = EDOM; return -HUGE_VAL; } } f = frexp(x, &n); if (f > _sqrt_half) { znum = (f - 0.5) - 0.5; zden = f * 0.5 + 0.5; } else { n -= 1; znum = f - 0.5; zden = znum * 0.5 + 0.5; } z = znum / zden; w = z * z; #define _log_a0 -0.64124943423745581147e2 #define _log_a1 0.16383943563021534222e2 #define _log_a2 -0.78956112887491257267e0 #define _log_b0 -0.76949932108494879777e3 #define _log_b1 0.31203222091924532844e3 #define _log_b2 -0.35667977739034646171e2 r = w * ( ((_log_a2 * w + _log_a1) * w + _log_a0) / (((w + _log_b2) * w + _log_b1) * w + _log_b0) ); r = z + z * r; xn = (double)n; return (xn*(-2.121944400546905827679e-4) + r) + xn*(355.0/512.0); } double log10(double x) { return log(x) * 0.43429448190325182765; /* log10(e) */ } double sqrt(double x) { fp_number f; double y0; int n; if (x <= 0.0) { if (x < 0.0) errno = EDOM; return -HUGE_VAL; } f.d = x; #ifdef IBMFLOAT n = f.i.x - 0x40; f.i.x = 0x40; #else n = f.i.x - 0x3fe; f.i.x = 0x3fe; #endif { double fd = f.d; #ifdef IBMFLOAT y0 = 0.223607 + 0.894427 * fd; #else y0 = 0.41731 + 0.59016 * fd; #endif y0 = 0.5 * (y0 + fd/y0); y0 = 0.5 * (y0 + fd/y0); y0 = 0.5 * (y0 + fd/y0); #ifdef IBMFLOAT #define __EPS 2.2204460492503131e-16 y0 = y0 + (0.5 * (fd/y0 - y0) + __EPS/32.0); #endif } if (n & 1) { #ifdef IBMFLOAT y0 = (y0 + __EPS/8.0) * 0.25; #else y0 *= _sqrt_half; #endif n += 1; } n /= 2; f.d = y0; f.i.x += n; return f.d; } double _tancot(double x, int iflag) { int n; double f, g, xnum, xden, y, xn; y = fabs(x); if (y >= 1.0e9) /* fail if argument is overlarge */ { errno = EDOM; return -HUGE_VAL; } n = (int) ((2.0 * y + _pi_2) / _pi_); if (x < 0) n = - n; xn = (double) n; #ifdef IBMFLOAT { double x1 = (double)(int)x; double x2 = x - x1; f = ((x1 - xn*1.57080078125) + x2) + xn*4.454455103380768678308e-6; } #else f = (x - xn*1.57080078125) + xn*4.454455103380768678308e-6; #endif if (fabs(f) > 1.e-10) { g = f * f; #define _tan_p1 -0.13338350006421960681 #define _tan_p2 0.34248878235890589960e-2 #define _tan_p3 -0.17861707342254426711e-4 #define _tan_q0 1.00000000000000000000 #define _tan_q1 -0.46671683339755294240 #define _tan_q2 0.25663832289440112864e-1 #define _tan_q3 -0.31181531907010027307e-3 #define _tan_q4 0.49819433993786512270e-6 xnum = ((_tan_p3*g + _tan_p2)*g + _tan_p1)*g*f + f; xden = (((_tan_q4*g + _tan_q3)*g + _tan_q2)*g + _tan_q1)*g + _tan_q0; } else { xnum = f; xden = 1.0; } /* It is probable that overflow can never occur here, since floating */ /* point values fall about or more 1.e-16 apart near singularities */ /* of the tangent function. */ if (iflag==0) { if ((n & 1) == 0) return xnum / xden; else return - xden / xnum; } else { if ((n & 1) == 0) return xden / xnum; else return - xnum / xden; } } double tan(double x) { return _tancot(x, 0); } double _cot(double x) /* Not specified by ANSI hence the funny name */ { if (fabs(x) < 1.0/HUGE_VAL) { errno = ERANGE; if (x < 0.0) return -HUGE_VAL; else return HUGE_VAL; } return _tancot(x, 1); } double atan(double x) { int n; double f; const static double a[4] = { 0.0, _pi_6, _pi_2, _pi_3 }; f = fabs(x); if (f > 1.0) { f = 1.0 / f; n = 2; } else n = 0; #define _two_minus_root_three 0.26794919243112270647 #define _sqrt_three 1.73205080756887729353 #define _sqrt_three_minus_one 0.73205080756887729353 if (f > _two_minus_root_three) { f = (((_sqrt_three_minus_one*f - 0.5) - 0.5) + f) / (_sqrt_three + f); n++; } if (fabs(f) > 1.e-10) { double g = f * f; double r; #define _atan_p0 -0.13688768894191926929e2 #define _atan_p1 -0.20505855195861651981e2 #define _atan_p2 -0.84946240351320683534e1 #define _atan_p3 -0.83758299368150059274 #define _atan_q0 0.41066306682575781263e2 #define _atan_q1 0.86157349597130242515e2 #define _atan_q2 0.59578436142597344465e2 #define _atan_q3 0.15024001160028576121e2 r = ((((_atan_p3*g + _atan_p2)*g + _atan_p1)*g + _atan_p0)*g) / ((((g + _atan_q3)*g + _atan_q2)*g + _atan_q1)*g + _atan_q0); f = f + f * r; } if (n > 1) f = -f; f = f + a[n]; if (x < 0) return -f; else return f; } double _asinacos(double x, int flag) { int i; double y, g, r; const static double a[2] = {0.0, _pi_4 }; const static double b[2] = {_pi_2, _pi_4 }; y = fabs(x); if (y < 1.e-10) i = flag; else { if (y > 0.5) { i = 1 - flag; if (y > 1.0) { errno = EDOM; return -HUGE_VAL; } g = ((0.5 - y) + 0.5) * 0.5; y = -2.0 * sqrt(g); } else { i = flag; g = y * y; } #define _asin_p1 -0.27368494524164255994e2 #define _asin_p2 0.57208227877891731407e2 #define _asin_p3 -0.39688862997504877339e2 #define _asin_p4 0.10152522233806463645e2 #define _asin_p5 -0.69674573447350646411e0 #define _asin_q0 -0.16421096714498560795e3 #define _asin_q1 0.41714430248260412556e3 #define _asin_q2 -0.38186303361750149284e3 #define _asin_q3 0.15095270841030604719e3 #define _asin_q4 -0.23823859153670238830e2 r = (((((_asin_p5*g + _asin_p4)*g + _asin_p3)*g + _asin_p2)*g + _asin_p1)*g) / (((((g + _asin_q4)*g + _asin_q3)*g + _asin_q2)*g + _asin_q1)*g + _asin_q0); y = y + y*r; } if (flag==0) { y = (a[i] + y) + a[i]; if (x<0) y = -y; } else if (x < 0) y = (b[i] + y) + b[i]; else y = (a[i] - y) + a[i]; return y; } double asin(double x) { return _asinacos(x, 0); } double acos(double x) { return _asinacos(x, 1); } double pow(double x, double y) { int sign = 0, m, p, i, mdash, pdash; double g, r, z, v, u1, u2; /* The table a1[] contains properly rounded values for 2**(i/16), and */ /* a2[] contains differences between the true values of 2**(i/16) and */ /* the a1[] values for odd i. */ #ifdef IBMFLOAT const static double a1[17] = { /* It is painfully important that the following 17 floating point */ /* numbers are read in to yield the quantities shown on the right. */ 1.000000000000000000, /* 41100000:00000000 */ 0.957603280698573644, /* 40f5257d:152486cc */ 0.917004043204671229, /* 40eac0c6:e7dd2439 */ 0.878126080186649740, /* 40e0ccde:ec2a94e1 */ 0.840896415253714543, /* 40d744fc:cad69d6b */ 0.805245165974627155, /* 40ce248c:151f8481 */ 0.771105412703970413, /* 40c5672a:115506db */ 0.738413072969749659, /* 40bd08a3:9f580c37 */ 0.707106781186547531, /* 40b504f3:33f9de65 */ 0.677127773468446367, /* 40ad583e:ea42a14b */ 0.648419777325504834, /* 40a5fed6:a9b15139 */ 0.620928906036742028, /* 409ef532:6091a112 */ 0.594603557501360527, /* 409837f0:518db8a9 */ 0.569394317378345823, /* 4091c3d3:73ab11c3 */ 0.545253866332628830, /* 408b95c1:e3ea8bd7 */ 0.522136891213706919, /* 4085aac3:67cc487b */ 0.500000000000000000 /* 40800000:00000000 */ }; const static double a2[8] = { 2.4114209503420287e-18, 9.2291566937243078e-19, -1.5241915231122319e-18, -3.5421849765286817e-18, -3.1286215245415074e-18, -4.4654376565694489e-18, 2.9305146686217562e-18, 1.1260851040933474e-18 }; #else /* IEEE format */ const static double a1[17] = { /* It is painfully important that the following 17 floating point */ /* numbers are read in to yield the quantities shown on the right. */ 1.0, /* 3ff00000:00000000 */ 0.9576032806985737, /* 3feea4af:a2a490da */ 0.91700404320467121, /* 3fed5818:dcfba487 */ 0.87812608018664973, /* 3fec199b:dd85529c */ 0.8408964152537145, /* 3feae89f:995ad3ad */ 0.80524516597462714, /* 3fe9c491:82a3f090 */ 0.77110541270397037, /* 3fe8ace5:422aa0db */ 0.73841307296974967, /* 3fe7a114:73eb0187 */ 0.70710678118654757, /* 3fe6a09e:667f3bcd */ 0.67712777346844632, /* 3fe5ab07:dd485429 */ 0.64841977732550482, /* 3fe4bfda:d5362a27 */ 0.620928906036742, /* 3fe3dea6:4c123422 */ 0.59460355750136051, /* 3fe306fe:0a31b715 */ 0.56939431737834578, /* 3fe2387a:6e756238 */ 0.54525386633262884, /* 3fe172b8:3c7d517b */ 0.52213689121370688, /* 3fe0b558:6cf9890f */ 0.5 /* 3fe00000:00000000 */ }; const static double a2[8] = { -5.3099730280915798e-17, 1.4800703477186887e-17, 1.2353596284702225e-17, -1.7419972784343138e-17, 3.8504741898901863e-17, 2.3290137959059465e-17, 4.4563878092065126e-17, 4.2759448527536718e-17 }; #endif if (y == 1.0) return x; if (x <= 0.0) { int ny; if (x==0.0) { if (y <= 0.0) { errno = EDOM; if (y==0.0) return 1.0; return -HUGE_VAL; } return 0.0; } if (y < (double)INT_MIN || y > (double)INT_MAX || (double)(ny = (int)y) != y) { errno = EDOM; return -HUGE_VAL; } /* Here y is an integer and x is negative. */ x = -x; sign = (ny & 1); } if (y == 2.0 && x < 1.e20) return x*x; /* special case. */ g = frexp(x, &m); p = 0; if (g <= a1[8]) p = 8; if (g <= a1[p+4]) p += 4; if (g <= a1[p+2]) p += 2; z = ((g - a1[p+1]) - a2[p/2]) / (0.5*g + 0.5*a1[p+1]); /* Expect abs(z) <= 0.044 here */ v = z * z; #define _pow_p1 0.83333333333333211405e-1 #define _pow_p2 0.12500000000503799174e-1 #define _pow_p3 0.22321421285924258967e-2 #define _pow_p4 0.43445775672163119635e-3 r = (((_pow_p4*v + _pow_p3)*v + _pow_p2)*v + _pow_p1)*v*z; #define _pow_k 0.44269504088896340736 r = r + _pow_k * r; u2 = (r + z * _pow_k) + z; #define _reduce(v) ((double)(int)(16.0*(v))*0.0625) u1 = (double)(16*m-p-1) * 0.0625; { double y1 = _reduce(y); double y2 = y - y1; double w = u2*y + u1*y2; double w1 = _reduce(w); double w2 = w - w1; int iw1; w = w1 + u1*y1; w1 = _reduce(w); w2 = w2 + (w - w1); w = _reduce(w2); iw1 = (int)(16.0*(w1+w)); w2 = w2 - w; /* The following values have been determined experimentally, buth their */ /* values are not very critical. */ #ifdef IBMFLOAT # define _negative_pow_limit -4160 #else # define _negative_pow_limit -16352 #endif if (iw1 < _negative_pow_limit) { errno = ERANGE; /* Underflow certain */ return 0.0; } if (w2 > 0.0) { iw1 += 1; w2 -= 0.0625; } if (iw1 < 0) i = 0; else i = 1; mdash = iw1/16 + i; pdash = 16*mdash - iw1; #define _pow_q1 0.69314718055994529629 #define _pow_q2 0.24022650695909537056 #define _pow_q3 0.55504108664085595326e-1 #define _pow_q4 0.96181290595172416964e-2 #define _pow_q5 0.13333541313585784703e-2 #define _pow_q6 0.15400290440989764601e-3 #define _pow_q7 0.14928852680595608186e-4 z = ((((((_pow_q7*w2 + _pow_q6)*w2 + _pow_q5)*w2 + _pow_q4)*w2 + _pow_q3)*w2 + _pow_q2)*w2 + _pow_q1)*w2; z = a1[pdash] + a1[pdash]*z; z = frexp(z, &m); mdash += m; #ifdef IBMFLOAT if (mdash > 0x3f*4) { errno = ERANGE; if (sign) r = -HUGE_VAL; else r = HUGE_VAL; } else if (mdash <= -0x41*4) { errno = ERANGE; r = 0.0; } #else if (mdash >= 0x7ff-0x3fe) { errno = ERANGE; if (sign) r = -HUGE_VAL; else r = HUGE_VAL; } else if (mdash <= -0x3fe) { errno = ERANGE; r = 0.0; } #endif else { r = ldexp(z, mdash); if (sign) r = -r; } } return r; } #endif /* HOST_HAS_TRIG */ double atan2(double y, double x) { if (x==0.0 && y==0.0) { errno = EDOM; return -HUGE_VAL; } if (fabs(x) < fabs(y)) { if (fabs(x / y)<1.0e-20) { if (y<0.0) return - _pi_2; else return _pi_2; } } y = atan(y / x); if (x<0.0) { if (y>0.0) y -= _pi_; else y += _pi_; } return y; } #undef fabs double fabs(double x) { if (x<0.0) return -x; else return x; } double sinh(double x) { int sign; double y; if (x<0.0) y = -x, sign = 1; else y = x, sign = 0; if (y>1.0) { /* _sinh_lnv is REQUIRED to read in as a number with the lower part of */ /* its floating point representation zero. */ #define _sinh_lnv 0.69316101074218750000 /* ln(v) */ #define _sinh_vm2 0.24999308500451499336 /* 1/v^2 */ #define _sinh_v2m1 0.13830277879601902638e-4 /* (v/2) - 1 */ double w = y - _sinh_lnv, z, r; if (w>_exp_arg_limit) { errno = ERANGE; if (sign) return -HUGE_VAL; else return HUGE_VAL; } z = exp(w); /* should not overflow! */ if (z < 1.0e10) z = z - _sinh_vm2/z; r = z + _sinh_v2m1 * z; if (sign) return -r; else return r; } else if (y<=1.0e-10) return x; else { #define _sinh_p0 -0.35181283430177117881e6 #define _sinh_p1 -0.11563521196851768270e5 #define _sinh_p2 -0.16375798202630751372e3 #define _sinh_p3 -0.78966127417357099479e0 #define _sinh_q0 -0.21108770058106271242e7 #define _sinh_q1 0.36162723109421836460e5 #define _sinh_q2 -0.27773523119650701667e3 #define _sinh_q3 1.0 double g = x*x; double r; /* Use a (minimax) rational approximation. See Cody & Waite. */ r = ((((_sinh_p3*g + _sinh_p2)*g + _sinh_p1)*g + _sinh_p0)*g) / (((g + _sinh_q2)*g + _sinh_q1)*g + _sinh_q0); return x + x*r; } } double cosh(double x) { if (x<0.0) x = -x; if (x>1.0) { x = x - _sinh_lnv; if (x>_exp_arg_limit) { errno = ERANGE; return HUGE_VAL; } x = exp(x); /* the range check above ensures that this does */ /* not overflow. */ if (x < 1.0e10) x = x + _sinh_vm2/x; /* This very final line might JUST overflow even though the call */ /* to exp is safe and even though _exp_arg_limit is conservative */ return x + _sinh_v2m1 * x; } /* This second part is satisfactory, even though it is simple! */ x = exp(x); return 0.5*(x + 1/x); } double tanh(double x) { /* The first two exits avoid premature overflow as well as needless use */ /* of the exp() function. */ int sign; if (x>27.0) return 1.0; /* here exp(2x) dominates 1.0 */ else if (x<-27.0) return -1.0; if (x<0.0) x = -x, sign = 1; else sign = 0; if (x>0.549306144334054846) /* ln(3)/2 is crossover point */ { x = exp(2.0*x); x = 1.0 - 2.0/(x + 1.0); if (sign) return -x; else return x; } #define _tanh_p0 -0.16134119023996228053e4 #define _tanh_p1 -0.99225929672236083313e2 #define _tanh_p2 -0.96437492777225469787e0 #define _tanh_q0 0.48402357071988688686e4 #define _tanh_q1 0.22337720718962312926e4 #define _tanh_q2 0.11274474380534949335e3 #define _tanh_q3 1.0 if (x>1.0e-10) { double y = x*x; /* minimax rational approximation */ y = (((_tanh_p2*y + _tanh_p1)*y + _tanh_p0)*y) / (((y + _tanh_q2)*y + _tanh_q1)*y + _tanh_q0); x = x + x*y; } if (sign) return -x; else return x; } double fmod(double x, double y) { /* floating point remainder of (x/y) for integral quotient. Remainder */ /* has same sign as x. */ double q, r; if (y==0.0) { errno = EDOM; return -HUGE_VAL; } if (x==0.0) return 0.0; if (y < 0.0) y = -y; r = modf(x/y, &q); r = x - q * y; /* The next few lines are an ultra-cautious scheme to ensure that the */ /* result is less than fabs(y) in value and that it has the sign of x. */ if (x > 0.0) { while (r >= y) r -= y; while (r < 0.0) r += y; } else { while (r <= -y) r += y; while (r > 0.0) r -= y; } return r; } #ifdef IBMFLOAT double floor(double d) { /* round x down to an integer towards minus infinity. */ fp_number x; int exponent, mask, exact; if (d == 0.0) return 0.0; x.d = d; /* pun on union type */ if ((exponent = x.i.x - 0x40) < 0) { if (x.i.s) return -1.0; else return 0.0; } else if (exponent >= 56/4) return x.d; if (exponent >= 24/4) { mask = ((unsigned) 0xffffffff) >> (4*(exponent - 24)); exact = x.i.mlo & mask; x.i.mlo &= ~mask; } else { mask = 0xfffff >> (4*exponent); exact = (x.i.mhi & mask) | x.i.mlo; x.i.mhi &= ~mask; x.i.mlo = 0; } if (exact!=0 && x.i.s) return x.d - 1.0; else return x.d; } double ceil(double d) { /* round x up to an integer towards plus infinity. */ fp_number x; int exponent, mask, exact; if (d == 0.0) return 0.0; x.d = d; /* pun on union type */ if ((exponent = x.i.x - 0x40) < 0) { if (x.i.s) return 0.0; else return 1.0; } else if (exponent >= 56/4) return x.d; if (exponent >= 24/4) { mask = ((unsigned) 0xffffffff) >> (4*(exponent - 24)); exact = x.i.mlo & mask; x.i.mlo &= ~mask; } else { mask = 0xfffff >> (4*exponent); exact = (x.i.mhi & mask) | x.i.mlo; x.i.mhi &= ~mask; x.i.mlo = 0; } if (exact!=0 && x.i.s==0) return x.d + 1.0; else return x.d; } double modf(double value, double *iptr) { /* splits value into integral part & fraction (both same sign) */ fp_number x; int exponent, mask; if (value == 0.0) { *iptr = 0.0; return 0.0; } x.d = value; if ((exponent = x.i.x - 0x40) < 0) { *iptr = 0.0; return value; } else if (exponent >= 56/4) { *iptr = value; return 0.0; } if (exponent >= 24/4) { mask = ((unsigned) 0xffffffff) >> (4*(exponent - 24)); x.i.mlo &= ~mask; } else { mask = 0xffffff >> (4*exponent); x.i.mhi &= ~mask; x.i.mlo = 0; } *iptr = x.d; return value - x.d; } #else /* IBMFLOAT */ double floor(double d) { /* round x down to an integer towards minus infinity. */ fp_number x; int exponent, mask, exact; if (d == 0.0) return 0.0; x.d = d; /* pun on union type */ if ((exponent = x.i.x - 0x3ff) < 0) { if (x.i.s) return -1.0; else return 0.0; } else if (exponent >= 52) return x.d; if (exponent >= 20) { mask = ((unsigned) 0xffffffff) >> (exponent - 20); exact = x.i.mlo & mask; x.i.mlo &= ~mask; } else { mask = 0xfffff >> exponent; exact = (x.i.mhi & mask) | x.i.mlo; x.i.mhi &= ~mask; x.i.mlo = 0; } if (exact!=0 && x.i.s) return x.d - 1.0; else return x.d; } double ceil(double d) { /* round x up to an integer towards plus infinity. */ fp_number x; int exponent, mask, exact; if (d == 0.0) return 0.0; x.d = d; /* pun on union type */ if ((exponent = x.i.x - 0x3ff) < 0) { if (x.i.s) return 0.0; else return 1.0; } else if (exponent >= 52) return x.d; if (exponent >= 20) { mask = ((unsigned) 0xffffffff) >> (exponent - 20); exact = x.i.mlo & mask; x.i.mlo &= ~mask; } else { mask = 0xfffff >> exponent; exact = (x.i.mhi & mask) | x.i.mlo; x.i.mhi &= ~mask; x.i.mlo = 0; } if (exact!=0 && x.i.s==0) return x.d + 1.0; else return x.d; } double modf(double value, double *iptr) { /* splits value into integral part & fraction (both same sign) */ fp_number x; int exponent, mask; if (value == 0.0) { *iptr = 0.0; return 0.0; } x.d = value; if ((exponent = x.i.x - 0x3ff) < 0) { *iptr = 0.0; return value; } else if (exponent >= 52) { *iptr = value; return 0.0; } if (exponent >= 20) { mask = ((unsigned) 0xffffffff) >> (exponent - 20); x.i.mlo &= ~mask; } else { mask = 0xfffff >> exponent; x.i.mhi &= ~mask; x.i.mlo = 0; } *iptr = x.d; return value - x.d; } #endif /* IBMFLOAT */ #endif /* NO_FLOATING_POINT */ /* end of math.c */