Index: fusl/src/math/expm1f.c |
diff --git a/fusl/src/math/expm1f.c b/fusl/src/math/expm1f.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..297e0b44a2ebcc99d406bc7641d1fbf8aa76b097 |
--- /dev/null |
+++ b/fusl/src/math/expm1f.c |
@@ -0,0 +1,111 @@ |
+/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ |
+/* |
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. |
+ */ |
+/* |
+ * ==================================================== |
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. |
+ * |
+ * Developed at SunPro, a Sun Microsystems, Inc. business. |
+ * Permission to use, copy, modify, and distribute this |
+ * software is freely granted, provided that this notice |
+ * is preserved. |
+ * ==================================================== |
+ */ |
+ |
+#include "libm.h" |
+ |
+static const float |
+o_threshold = 8.8721679688e+01, /* 0x42b17180 */ |
+ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ |
+ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ |
+invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ |
+/* |
+ * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: |
+ * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 |
+ * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): |
+ */ |
+Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */ |
+Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ |
+ |
+float expm1f(float x) |
+{ |
+ float_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; |
+ union {float f; uint32_t i;} u = {x}; |
+ uint32_t hx = u.i & 0x7fffffff; |
+ int k, sign = u.i >> 31; |
+ |
+ /* filter out huge and non-finite argument */ |
+ if (hx >= 0x4195b844) { /* if |x|>=27*ln2 */ |
+ if (hx > 0x7f800000) /* NaN */ |
+ return x; |
+ if (sign) |
+ return -1; |
+ if (x > o_threshold) { |
+ x *= 0x1p127f; |
+ return x; |
+ } |
+ } |
+ |
+ /* argument reduction */ |
+ if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ |
+ if (hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ |
+ if (!sign) { |
+ hi = x - ln2_hi; |
+ lo = ln2_lo; |
+ k = 1; |
+ } else { |
+ hi = x + ln2_hi; |
+ lo = -ln2_lo; |
+ k = -1; |
+ } |
+ } else { |
+ k = invln2*x + (sign ? -0.5f : 0.5f); |
+ t = k; |
+ hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ |
+ lo = t*ln2_lo; |
+ } |
+ x = hi-lo; |
+ c = (hi-x)-lo; |
+ } else if (hx < 0x33000000) { /* when |x|<2**-25, return x */ |
+ if (hx < 0x00800000) |
+ FORCE_EVAL(x*x); |
+ return x; |
+ } else |
+ k = 0; |
+ |
+ /* x is now in primary range */ |
+ hfx = 0.5f*x; |
+ hxs = x*hfx; |
+ r1 = 1.0f+hxs*(Q1+hxs*Q2); |
+ t = 3.0f - r1*hfx; |
+ e = hxs*((r1-t)/(6.0f - x*t)); |
+ if (k == 0) /* c is 0 */ |
+ return x - (x*e-hxs); |
+ e = x*(e-c) - c; |
+ e -= hxs; |
+ /* exp(x) ~ 2^k (x_reduced - e + 1) */ |
+ if (k == -1) |
+ return 0.5f*(x-e) - 0.5f; |
+ if (k == 1) { |
+ if (x < -0.25f) |
+ return -2.0f*(e-(x+0.5f)); |
+ return 1.0f + 2.0f*(x-e); |
+ } |
+ u.i = (0x7f+k)<<23; /* 2^k */ |
+ twopk = u.f; |
+ if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ |
+ y = x - e + 1.0f; |
+ if (k == 128) |
+ y = y*2.0f*0x1p127f; |
+ else |
+ y = y*twopk; |
+ return y - 1.0f; |
+ } |
+ u.i = (0x7f-k)<<23; /* 2^-k */ |
+ if (k < 23) |
+ y = (x-e+(1-u.f))*twopk; |
+ else |
+ y = (x-(e+u.f)+1)*twopk; |
+ return y; |
+} |