diff options
author | Piotr Jasiukajtis <estibi@me.com> | 2014-02-04 20:31:57 +0100 |
---|---|---|
committer | Dan McDonald <danmcd@omniti.com> | 2014-10-17 18:00:52 -0400 |
commit | 25c28e83beb90e7c80452a7c818c5e6f73a07dc8 (patch) | |
tree | 95cb102e7fb37f52d4b3ec3e44508f352a335ee5 /usr/src/lib/libm/common/Q/logl.c | |
parent | 4e6070e87069f63bef94d8e79c2fc3cab2c1ab6b (diff) | |
download | illumos-gate-25c28e83beb90e7c80452a7c818c5e6f73a07dc8.tar.gz |
693 Opensource replacement of sunwlibm
Reviewed by: Igor Kozhukhov ikozhukhov@gmail.com
Reviewed by: Keith M Wesolowski <keith.wesolowski@joyent.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Dan McDonald <danmcd@omniti.com>
Diffstat (limited to 'usr/src/lib/libm/common/Q/logl.c')
-rw-r--r-- | usr/src/lib/libm/common/Q/logl.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/usr/src/lib/libm/common/Q/logl.c b/usr/src/lib/libm/common/Q/logl.c new file mode 100644 index 0000000000..1cdf224c07 --- /dev/null +++ b/usr/src/lib/libm/common/Q/logl.c @@ -0,0 +1,173 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma weak logl = __logl + +/* + * logl(x) + * Table look-up algorithm + * By K.C. Ng, March 6, 1989 + * + * (a). For x in [31/33,33/31], using a special approximation: + * f = x - 1; + * s = f/(2.0+f); ... here |s| <= 0.03125 + * z = s*s; + * return f-s*(f-z*(B1+z*(B2+z*(B3+z*(B4+...+z*B9)...)))); + * + * (b). Otherwise, normalize x = 2^n * 1.f. + * Use a 6-bit table look-up: find a 6 bit g that match f to 6.5 bits, + * then + * log(x) = n*ln2 + log(1.g) + log(1.f/1.g). + * Here the leading and trailing values of log(1.g) are obtained from + * a size-64 table. + * For log(1.f/1.g), let s = (1.f-1.g)/(1.f+1.g), then + * log(1.f/1.g) = log((1+s)/(1-s)) = 2s + 2/3 s^3 + 2/5 s^5 +... + * Note that |s|<2**-8=0.00390625. We use an odd s-polynomial + * approximation to compute log(1.f/1.g): + * s*(A1+s^2*(A2+s^2*(A3+s^2*(A4+s^2*(A5+s^2*(A6+s^2*A7)))))) + * (Precision is 2**-136.91 bits, absolute error) + * + * (c). The final result is computed by + * (n*ln2_hi+_TBL_logl_hi[j]) + + * ( (n*ln2_lo+_TBL_logl_lo[j]) + s*(A1+...) ) + * + * Note. + * For ln2_hi and _TBL_logl_hi[j], we force their last 32 bit to be zero + * so that n*ln2_hi + _TBL_logl_hi[j] is exact. Here + * _TBL_logl_hi[j] + _TBL_logl_lo[j] match log(1+j*2**-6) to 194 bits + * + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Constants: + * The hexadecimal values are the intended ones for the following constants. + * The decimal values may be used, provided that the compiler will convert + * from decimal to binary accurately enough to produce the hexadecimal values + * shown. + */ + +#include "libm.h" + +extern const long double _TBL_logl_hi[], _TBL_logl_lo[]; + +static const long double + zero = 0.0L, + one = 1.0L, + two = 2.0L, + two113 = 10384593717069655257060992658440192.0L, + ln2hi = 6.931471805599453094172319547495844850203e-0001L, + ln2lo = 1.667085920830552208890449330400379754169e-0025L, + A1 = 2.000000000000000000000000000000000000024e+0000L, + A2 = 6.666666666666666666666666666666091393804e-0001L, + A3 = 4.000000000000000000000000407167070220671e-0001L, + A4 = 2.857142857142857142730077490612903681164e-0001L, + A5 = 2.222222222222242577702836920812882605099e-0001L, + A6 = 1.818181816435493395985912667105885828356e-0001L, + A7 = 1.538537835211839751112067512805496931725e-0001L, + B1 = 6.666666666666666666666666666666961498329e-0001L, + B2 = 3.999999999999999999999999990037655042358e-0001L, + B3 = 2.857142857142857142857273426428347457918e-0001L, + B4 = 2.222222222222222221353229049747910109566e-0001L, + B5 = 1.818181818181821503532559306309070138046e-0001L, + B6 = 1.538461538453809210486356084587356788556e-0001L, + B7 = 1.333333344463358756121456892645178795480e-0001L, + B8 = 1.176460904783899064854645174603360383792e-0001L, + B9 = 1.057293869956598995326368602518056990746e-0001L; + +long double +logl(long double x) { + long double f, s, z, qn, h, t; + int *px = (int *) &x; + int *pz = (int *) &z; + int i, j, ix, i0, i1, n; + + /* get long double precision word ordering */ + if (*(int *) &one == 0) { + i0 = 3; + i1 = 0; + } else { + i0 = 0; + i1 = 3; + } + + n = 0; + ix = px[i0]; + if (ix > 0x3ffee0f8) { /* if x > 31/33 */ + if (ix < 0x3fff1084) { /* if x < 33/31 */ + f = x - one; + z = f * f; + if (((ix - 0x3fff0000) | px[i1] | px[2] | px[1]) == 0) { + return (zero); /* log(1)= +0 */ + } + s = f / (two + f); /* |s|<2**-8 */ + z = s * s; + return (f - s * (f - z * (B1 + z * (B2 + z * (B3 + + z * (B4 + z * (B5 + z * (B6 + z * (B7 + + z * (B8 + z * B9)))))))))); + } + if (ix >= 0x7fff0000) + return (x + x); /* x is +inf or NaN */ + goto LARGE_N; + } + if (ix >= 0x00010000) + goto LARGE_N; + i = ix & 0x7fffffff; + if ((i | px[i1] | px[2] | px[1]) == 0) { + px[i0] |= 0x80000000; + return (one / x); /* log(0.0) = -inf */ + } + if (ix < 0) { + if ((unsigned) ix >= 0xffff0000) + return (x - x); /* x is -inf or NaN */ + return (zero / zero); /* log(x<0) is NaN */ + } + /* subnormal x */ + x *= two113; + n = -113; + ix = px[i0]; +LARGE_N: + n += ((ix + 0x200) >> 16) - 0x3fff; + ix = (ix & 0x0000ffff) | 0x3fff0000; /* scale x to [1,2] */ + px[i0] = ix; + i = ix + 0x200; + pz[i0] = i & 0xfffffc00; + pz[i1] = pz[1] = pz[2] = 0; + s = (x - z) / (x + z); + j = (i >> 10) & 0x3f; + z = s * s; + qn = (long double) n; + t = qn * ln2lo + _TBL_logl_lo[j]; + h = qn * ln2hi + _TBL_logl_hi[j]; + f = t + s * (A1 + z * (A2 + z * (A3 + z * (A4 + z * (A5 + + z * (A6 + z * A7)))))); + return (h + f); +} |