about summary refs log tree commit diff
path: root/src/math
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-02-12 00:22:29 -0500
committerRich Felker <dalias@aerifal.cx>2011-02-12 00:22:29 -0500
commit0b44a0315b47dd8eced9f3b7f31580cf14bbfc01 (patch)
tree6eaef0d8a720fa3da580de87b647fff796fe80b3 /src/math
downloadmusl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.tar.gz
musl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.tar.xz
musl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.zip
initial check-in, version 0.5.0 v0.5.0
Diffstat (limited to 'src/math')
-rw-r--r--src/math/__fpclassify.c14
-rw-r--r--src/math/__fpclassifyf.c14
-rw-r--r--src/math/__fpclassifyl.c16
-rw-r--r--src/math/e_acos.c99
-rw-r--r--src/math/e_acosf.c77
-rw-r--r--src/math/e_acosh.c59
-rw-r--r--src/math/e_acoshf.c45
-rw-r--r--src/math/e_asin.c109
-rw-r--r--src/math/e_asinf.c80
-rw-r--r--src/math/e_atan2.c120
-rw-r--r--src/math/e_atan2f.c93
-rw-r--r--src/math/e_atanh.c59
-rw-r--r--src/math/e_atanhf.c42
-rw-r--r--src/math/e_cosh.c82
-rw-r--r--src/math/e_coshf.c59
-rw-r--r--src/math/e_exp.c155
-rw-r--r--src/math/e_expf.c91
-rw-r--r--src/math/e_fmod.c129
-rw-r--r--src/math/e_fmodf.c101
-rw-r--r--src/math/e_hypot.c121
-rw-r--r--src/math/e_hypotf.c79
-rw-r--r--src/math/e_log.c131
-rw-r--r--src/math/e_log10.c83
-rw-r--r--src/math/e_log10f.c51
-rw-r--r--src/math/e_logf.c81
-rw-r--r--src/math/e_pow.c300
-rw-r--r--src/math/e_powf.c243
-rw-r--r--src/math/e_rem_pio2.c163
-rw-r--r--src/math/e_rem_pio2f.c175
-rw-r--r--src/math/e_remainder.c69
-rw-r--r--src/math/e_remainderf.c61
-rw-r--r--src/math/e_scalb.c35
-rw-r--r--src/math/e_scalbf.c31
-rw-r--r--src/math/e_sinh.c75
-rw-r--r--src/math/e_sinhf.c56
-rw-r--r--src/math/e_sqrt.c442
-rw-r--r--src/math/e_sqrtf.c85
-rw-r--r--src/math/i386/e_exp.s36
-rw-r--r--src/math/i386/e_expf.s1
-rw-r--r--src/math/i386/e_log.s6
-rw-r--r--src/math/i386/e_log10.s6
-rw-r--r--src/math/i386/e_log10f.s6
-rw-r--r--src/math/i386/e_logf.s6
-rw-r--r--src/math/i386/e_remainder.s16
-rw-r--r--src/math/i386/e_remainderf.s0
-rw-r--r--src/math/i386/e_sqrt.s4
-rw-r--r--src/math/i386/e_sqrtf.s4
-rw-r--r--src/math/i386/s_ceil.s0
-rw-r--r--src/math/i386/s_ceilf.s0
-rw-r--r--src/math/i386/s_fabs.s5
-rw-r--r--src/math/i386/s_fabsf.s5
-rw-r--r--src/math/i386/s_floor.s0
-rw-r--r--src/math/i386/s_floorf.s0
-rw-r--r--src/math/i386/s_ldexp.s0
-rw-r--r--src/math/i386/s_ldexpf.s0
-rw-r--r--src/math/i386/s_rint.s5
-rw-r--r--src/math/i386/s_rintf.s5
-rw-r--r--src/math/i386/s_scalbln.s11
-rw-r--r--src/math/i386/s_scalblnf.s11
-rw-r--r--src/math/i386/s_trunc.s36
-rw-r--r--src/math/i386/s_truncf.s0
-rw-r--r--src/math/k_cos.c85
-rw-r--r--src/math/k_cosf.c52
-rw-r--r--src/math/k_rem_pio2.c300
-rw-r--r--src/math/k_rem_pio2f.c192
-rw-r--r--src/math/k_sin.c68
-rw-r--r--src/math/k_sinf.c42
-rw-r--r--src/math/k_tan.c149
-rw-r--r--src/math/k_tanf.c105
-rw-r--r--src/math/math_private.h143
-rw-r--r--src/math/s_asinh.c53
-rw-r--r--src/math/s_asinhf.c45
-rw-r--r--src/math/s_atan.c115
-rw-r--r--src/math/s_atanf.c95
-rw-r--r--src/math/s_cbrt.c77
-rw-r--r--src/math/s_cbrtf.c67
-rw-r--r--src/math/s_ceil.c68
-rw-r--r--src/math/s_ceilf.c49
-rw-r--r--src/math/s_copysign.c30
-rw-r--r--src/math/s_copysignf.c33
-rw-r--r--src/math/s_cos.c74
-rw-r--r--src/math/s_cosf.c47
-rw-r--r--src/math/s_erf.c298
-rw-r--r--src/math/s_erff.c207
-rw-r--r--src/math/s_expm1.c217
-rw-r--r--src/math/s_expm1f.c122
-rw-r--r--src/math/s_fabs.c27
-rw-r--r--src/math/s_fabsf.c30
-rw-r--r--src/math/s_floor.c69
-rw-r--r--src/math/s_floorf.c58
-rw-r--r--src/math/s_ilogb.c45
-rw-r--r--src/math/s_ilogbf.c37
-rw-r--r--src/math/s_ldexp.c6
-rw-r--r--src/math/s_ldexpf.c6
-rw-r--r--src/math/s_llrint.c8
-rw-r--r--src/math/s_log1p.c157
-rw-r--r--src/math/s_log1pf.c96
-rw-r--r--src/math/s_logb.c34
-rw-r--r--src/math/s_logbf.c31
-rw-r--r--src/math/s_lrint.c8
-rw-r--r--src/math/s_lrintf.c8
-rw-r--r--src/math/s_modf.c71
-rw-r--r--src/math/s_modff.c52
-rw-r--r--src/math/s_nextafter.c72
-rw-r--r--src/math/s_nextafterf.c63
-rw-r--r--src/math/s_remquo.c149
-rw-r--r--src/math/s_remquof.c118
-rw-r--r--src/math/s_rint.c80
-rw-r--r--src/math/s_rintf.c45
-rw-r--r--src/math/s_round.c48
-rw-r--r--src/math/s_roundf.c48
-rw-r--r--src/math/s_scalbln.c61
-rw-r--r--src/math/s_scalblnf.c57
-rw-r--r--src/math/s_sin.c74
-rw-r--r--src/math/s_sinf.c45
-rw-r--r--src/math/s_tan.c68
-rw-r--r--src/math/s_tanf.c40
-rw-r--r--src/math/s_tanh.c74
-rw-r--r--src/math/s_tanhf.c52
-rw-r--r--src/math/s_trunc.c58
-rw-r--r--src/math/s_truncf.c50
121 files changed, 8566 insertions, 0 deletions
diff --git a/src/math/__fpclassify.c b/src/math/__fpclassify.c
new file mode 100644
index 00000000..16051100
--- /dev/null
+++ b/src/math/__fpclassify.c
@@ -0,0 +1,14 @@
+#include <stdint.h>
+#include <math.h>
+
+int __fpclassify(double __x)
+{
+	union {
+		double __d;
+		__uint64_t __i;
+	} __y = { __x };
+	int __ee = __y.__i>>52 & 0x7ff;
+	if (!__ee) return __y.__i<<1 ? FP_SUBNORMAL : FP_ZERO;
+	if (__ee==0x7ff) return __y.__i<<12 ? FP_NAN : FP_INFINITE;
+	return FP_NORMAL;
+}
diff --git a/src/math/__fpclassifyf.c b/src/math/__fpclassifyf.c
new file mode 100644
index 00000000..bf59d0d4
--- /dev/null
+++ b/src/math/__fpclassifyf.c
@@ -0,0 +1,14 @@
+#include <stdint.h>
+#include <math.h>
+
+int __fpclassifyf(float __x)
+{
+	union {
+		float __f;
+		__uint32_t __i;
+	} __y = { __x };
+	int __ee = __y.__i>>23 & 0xff;
+	if (!__ee) return __y.__i<<1 ? FP_SUBNORMAL : FP_ZERO;
+	if (__ee==0xff) return __y.__i<<9 ? FP_NAN : FP_INFINITE;
+	return FP_NORMAL;
+}
diff --git a/src/math/__fpclassifyl.c b/src/math/__fpclassifyl.c
new file mode 100644
index 00000000..4f93bef1
--- /dev/null
+++ b/src/math/__fpclassifyl.c
@@ -0,0 +1,16 @@
+#include <stdint.h>
+#include <math.h>
+
+/* FIXME: move this to arch-specific file */
+int __fpclassifyl(long double __x)
+{
+	union {
+		long double __ld;
+		__uint16_t __hw[5];
+		__uint64_t __m;
+	} __y = { __x };
+	int __ee = __y.__hw[4]&0x7fff;
+	if (!__ee) return __y.__m ? FP_SUBNORMAL : FP_ZERO;
+	if (__ee==0x7fff) return __y.__m ? FP_NAN : FP_INFINITE;
+	return FP_NORMAL;
+}
diff --git a/src/math/e_acos.c b/src/math/e_acos.c
new file mode 100644
index 00000000..e0236391
--- /dev/null
+++ b/src/math/e_acos.c
@@ -0,0 +1,99 @@
+/* @(#)e_acos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* acos(x)
+ * Method :                  
+ *      acos(x)  = pi/2 - asin(x)
+ *      acos(-x) = pi/2 + asin(x)
+ * For |x|<=0.5
+ *      acos(x) = pi/2 - (x + x*x^2*R(x^2))     (see asin.c)
+ * For x>0.5
+ *      acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
+ *              = 2asin(sqrt((1-x)/2))  
+ *              = 2s + 2s*z*R(z)        ...z=(1-x)/2, s=sqrt(z)
+ *              = 2f + (2c + 2s*z*R(z))
+ *     where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
+ *     for f so that f+c ~ sqrt(z).
+ * For x<-0.5
+ *      acos(x) = pi - 2asin(sqrt((1-|x|)/2))
+ *              = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
+ *
+ * Special cases:
+ *      if x is NaN, return x itself;
+ *      if |x|>1, return NaN with invalid signal.
+ *
+ * Function needed: sqrt
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one=  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi =  3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+pio2_hi =  1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo =  6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 =  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 =  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+double
+acos(double x)
+{
+        double z,p,q,r,w,s,c,df;
+        int32_t hx,ix;
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x3ff00000) {    /* |x| >= 1 */
+            uint32_t lx;
+            GET_LOW_WORD(lx,x);
+            if(((ix-0x3ff00000)|lx)==0) {       /* |x|==1 */
+                if(hx>0) return 0.0;            /* acos(1) = 0  */
+                else return pi+2.0*pio2_lo;     /* acos(-1)= pi */
+            }
+            return (x-x)/(x-x);         /* acos(|x|>1) is NaN */
+        }
+        if(ix<0x3fe00000) {     /* |x| < 0.5 */
+            if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+            z = x*x;
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            r = p/q;
+            return pio2_hi - (x - (pio2_lo-x*r));
+        } else  if (hx<0) {             /* x < -0.5 */
+            z = (one+x)*0.5;
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            s = sqrt(z);
+            r = p/q;
+            w = r*s-pio2_lo;
+            return pi - 2.0*(s+w);
+        } else {                        /* x > 0.5 */
+            z = (one-x)*0.5;
+            s = sqrt(z);
+            df = s;
+            SET_LOW_WORD(df,0);
+            c  = (z-df*df)/(s+df);
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            r = p/q;
+            w = r*s+c;
+            return 2.0*(df+w);
+        }
+}
diff --git a/src/math/e_acosf.c b/src/math/e_acosf.c
new file mode 100644
index 00000000..4c59781b
--- /dev/null
+++ b/src/math/e_acosf.c
@@ -0,0 +1,77 @@
+/* e_acosf.c -- float version of e_acos.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 <math.h>
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3F800000 */
+pi =  3.1415925026e+00, /* 0x40490fda */
+pio2_hi =  1.5707962513e+00, /* 0x3fc90fda */
+pio2_lo =  7.5497894159e-08, /* 0x33a22168 */
+pS0 =  1.6666667163e-01, /* 0x3e2aaaab */
+pS1 = -3.2556581497e-01, /* 0xbea6b090 */
+pS2 =  2.0121252537e-01, /* 0x3e4e0aa8 */
+pS3 = -4.0055535734e-02, /* 0xbd241146 */
+pS4 =  7.9153501429e-04, /* 0x3a4f7f04 */
+pS5 =  3.4793309169e-05, /* 0x3811ef08 */
+qS1 = -2.4033949375e+00, /* 0xc019d139 */
+qS2 =  2.0209457874e+00, /* 0x4001572d */
+qS3 = -6.8828397989e-01, /* 0xbf303361 */
+qS4 =  7.7038154006e-02; /* 0x3d9dc62e */
+
+float
+acosf(float x)
+{
+        float z,p,q,r,w,s,c,df;
+        int32_t hx,ix;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix==0x3f800000) {            /* |x|==1 */
+            if(hx>0) return 0.0;        /* acos(1) = 0  */
+            else return pi+(float)2.0*pio2_lo;  /* acos(-1)= pi */
+        } else if(ix>0x3f800000) {      /* |x| >= 1 */
+            return (x-x)/(x-x);         /* acos(|x|>1) is NaN */
+        }
+        if(ix<0x3f000000) {     /* |x| < 0.5 */
+            if(ix<=0x23000000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+            z = x*x;
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            r = p/q;
+            return pio2_hi - (x - (pio2_lo-x*r));
+        } else  if (hx<0) {             /* x < -0.5 */
+            z = (one+x)*(float)0.5;
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            s = sqrtf(z);
+            r = p/q;
+            w = r*s-pio2_lo;
+            return pi - (float)2.0*(s+w);
+        } else {                        /* x > 0.5 */
+            int32_t idf;
+            z = (one-x)*(float)0.5;
+            s = sqrtf(z);
+            df = s;
+            GET_FLOAT_WORD(idf,df);
+            SET_FLOAT_WORD(df,idf&0xfffff000);
+            c  = (z-df*df)/(s+df);
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            r = p/q;
+            w = r*s+c;
+            return (float)2.0*(df+w);
+        }
+}
diff --git a/src/math/e_acosh.c b/src/math/e_acosh.c
new file mode 100644
index 00000000..8b454e75
--- /dev/null
+++ b/src/math/e_acosh.c
@@ -0,0 +1,59 @@
+
+/* @(#)e_acosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* acosh(x)
+ * Method :
+ *      Based on 
+ *              acosh(x) = log [ x + sqrt(x*x-1) ]
+ *      we have
+ *              acosh(x) := log(x)+ln2, if x is large; else
+ *              acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+ *              acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ *      acosh(x) is NaN with signal if x<1.
+ *      acosh(NaN) is NaN without signal.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one     = 1.0,
+ln2     = 6.93147180559945286227e-01;  /* 0x3FE62E42, 0xFEFA39EF */
+
+double
+acosh(double x)
+{
+        double t;
+        int32_t hx;
+        uint32_t lx;
+        EXTRACT_WORDS(hx,lx,x);
+        if(hx<0x3ff00000) {             /* x < 1 */
+            return (x-x)/(x-x);
+        } else if(hx >=0x41b00000) {    /* x > 2**28 */
+            if(hx >=0x7ff00000) {       /* x is inf of NaN */
+                return x+x;
+            } else 
+                return log(x)+ln2;    /* acosh(huge)=log(2x) */
+        } else if(((hx-0x3ff00000)|lx)==0) {
+            return 0.0;                 /* acosh(1) = 0 */
+        } else if (hx > 0x40000000) {   /* 2**28 > x > 2 */
+            t=x*x;
+            return log(2.0*x-one/(x+sqrt(t-one)));
+        } else {                        /* 1<x<2 */
+            t = x-one;
+            return log1p(t+sqrt(2.0*t+t*t));
+        }
+}
diff --git a/src/math/e_acoshf.c b/src/math/e_acoshf.c
new file mode 100644
index 00000000..b7f1df69
--- /dev/null
+++ b/src/math/e_acoshf.c
@@ -0,0 +1,45 @@
+/* e_acoshf.c -- float version of e_acosh.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 <math.h>
+#include "math_private.h"
+
+static const float
+one     = 1.0,
+ln2     = 6.9314718246e-01;  /* 0x3f317218 */
+
+float
+acoshf(float x)
+{
+        float t;
+        int32_t hx;
+        GET_FLOAT_WORD(hx,x);
+        if(hx<0x3f800000) {             /* x < 1 */
+            return (x-x)/(x-x);
+        } else if(hx >=0x4d800000) {    /* x > 2**28 */
+            if(hx >=0x7f800000) {       /* x is inf of NaN */
+                return x+x;
+            } else
+                return logf(x)+ln2;     /* acosh(huge)=log(2x) */
+        } else if (hx==0x3f800000) {
+            return 0.0;                 /* acosh(1) = 0 */
+        } else if (hx > 0x40000000) {   /* 2**28 > x > 2 */
+            t=x*x;
+            return logf((float)2.0*x-one/(x+sqrtf(t-one)));
+        } else {                        /* 1<x<2 */
+            t = x-one;
+            return log1pf(t+sqrtf((float)2.0*t+t*t));
+        }
+}
diff --git a/src/math/e_asin.c b/src/math/e_asin.c
new file mode 100644
index 00000000..4bf162a1
--- /dev/null
+++ b/src/math/e_asin.c
@@ -0,0 +1,109 @@
+
+/* @(#)e_asin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* asin(x)
+ * Method :                  
+ *      Since  asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
+ *      we approximate asin(x) on [0,0.5] by
+ *              asin(x) = x + x*x^2*R(x^2)
+ *      where
+ *              R(x^2) is a rational approximation of (asin(x)-x)/x^3 
+ *      and its remez error is bounded by
+ *              |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
+ *
+ *      For x in [0.5,1]
+ *              asin(x) = pi/2-2*asin(sqrt((1-x)/2))
+ *      Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
+ *      then for x>0.98
+ *              asin(x) = pi/2 - 2*(s+s*z*R(z))
+ *                      = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
+ *      For x<=0.98, let pio4_hi = pio2_hi/2, then
+ *              f = hi part of s;
+ *              c = sqrt(z) - f = (z-f*f)/(s+f)         ...f+c=sqrt(z)
+ *      and
+ *              asin(x) = pi/2 - 2*(s+s*z*R(z))
+ *                      = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
+ *                      = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
+ *
+ * Special cases:
+ *      if x is NaN, return x itself;
+ *      if |x|>1, return NaN with invalid signal.
+ *
+ */
+
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+huge =  1.000e+300,
+pio2_hi =  1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo =  6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pio4_hi =  7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+        /* coefficient for R(x^2) */
+pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 =  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 =  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+double
+asin(double x)
+{
+        double t=0.0,w,p,q,c,r,s;
+        int32_t hx,ix;
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>= 0x3ff00000) {           /* |x|>= 1 */
+            uint32_t lx;
+            GET_LOW_WORD(lx,x);
+            if(((ix-0x3ff00000)|lx)==0)
+                    /* asin(1)=+-pi/2 with inexact */
+                return x*pio2_hi+x*pio2_lo;     
+            return (x-x)/(x-x);         /* asin(|x|>1) is NaN */   
+        } else if (ix<0x3fe00000) {     /* |x|<0.5 */
+            if(ix<0x3e400000) {         /* if |x| < 2**-27 */
+                if(huge+x>one) return x;/* return x with inexact if x!=0*/
+            } else 
+                t = x*x;
+                p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+                q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+                w = p/q;
+                return x+x*w;
+        }
+        /* 1> |x|>= 0.5 */
+        w = one-fabs(x);
+        t = w*0.5;
+        p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+        q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+        s = sqrt(t);
+        if(ix>=0x3FEF3333) {    /* if |x| > 0.975 */
+            w = p/q;
+            t = pio2_hi-(2.0*(s+s*w)-pio2_lo);
+        } else {
+            w  = s;
+            SET_LOW_WORD(w,0);
+            c  = (t-w*w)/(s+w);
+            r  = p/q;
+            p  = 2.0*s*r-(pio2_lo-2.0*c);
+            q  = pio4_hi-2.0*w;
+            t  = pio4_hi-(p-q);
+        }    
+        if(hx>0) return t; else return -t;    
+}
diff --git a/src/math/e_asinf.c b/src/math/e_asinf.c
new file mode 100644
index 00000000..9c693970
--- /dev/null
+++ b/src/math/e_asinf.c
@@ -0,0 +1,80 @@
+/* e_asinf.c -- float version of e_asin.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 <math.h>
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3F800000 */
+huge =  1.000e+30,
+pio2_hi =  1.5707962513e+00, /* 0x3fc90fda */
+pio2_lo =  7.5497894159e-08, /* 0x33a22168 */
+pio4_hi =  7.8539818525e-01, /* 0x3f490fdb */
+	/* coefficient for R(x^2) */
+pS0 =  1.6666667163e-01, /* 0x3e2aaaab */
+pS1 = -3.2556581497e-01, /* 0xbea6b090 */
+pS2 =  2.0121252537e-01, /* 0x3e4e0aa8 */
+pS3 = -4.0055535734e-02, /* 0xbd241146 */
+pS4 =  7.9153501429e-04, /* 0x3a4f7f04 */
+pS5 =  3.4793309169e-05, /* 0x3811ef08 */
+qS1 = -2.4033949375e+00, /* 0xc019d139 */
+qS2 =  2.0209457874e+00, /* 0x4001572d */
+qS3 = -6.8828397989e-01, /* 0xbf303361 */
+qS4 =  7.7038154006e-02; /* 0x3d9dc62e */
+
+float
+asinf(float x)
+{
+	float t=0.0,w,p,q,c,r,s;
+	int32_t hx,ix;
+	GET_FLOAT_WORD(hx,x);
+	ix = hx&0x7fffffff;
+	if(ix==0x3f800000) {
+		/* asin(1)=+-pi/2 with inexact */
+	    return x*pio2_hi+x*pio2_lo;
+	} else if(ix> 0x3f800000) {	/* |x|>= 1 */
+	    return (x-x)/(x-x);		/* asin(|x|>1) is NaN */
+	} else if (ix<0x3f000000) {	/* |x|<0.5 */
+	    if(ix<0x32000000) {		/* if |x| < 2**-27 */
+		if(huge+x>one) return x;/* return x with inexact if x!=0*/
+	    } else
+		t = x*x;
+		p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+		q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+		w = p/q;
+		return x+x*w;
+	}
+	/* 1> |x|>= 0.5 */
+	w = one-fabsf(x);
+	t = w*(float)0.5;
+	p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+	q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+	s = sqrtf(t);
+	if(ix>=0x3F79999A) { 	/* if |x| > 0.975 */
+	    w = p/q;
+	    t = pio2_hi-((float)2.0*(s+s*w)-pio2_lo);
+	} else {
+	    int32_t iw;
+	    w  = s;
+	    GET_FLOAT_WORD(iw,w);
+	    SET_FLOAT_WORD(w,iw&0xfffff000);
+	    c  = (t-w*w)/(s+w);
+	    r  = p/q;
+	    p  = (float)2.0*s*r-(pio2_lo-(float)2.0*c);
+	    q  = pio4_hi-(float)2.0*w;
+	    t  = pio4_hi-(p-q);
+	}
+	if(hx>0) return t; else return -t;
+}
diff --git a/src/math/e_atan2.c b/src/math/e_atan2.c
new file mode 100644
index 00000000..dd021164
--- /dev/null
+++ b/src/math/e_atan2.c
@@ -0,0 +1,120 @@
+
+/* @(#)e_atan2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* atan2(y,x)
+ * Method :
+ *      1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
+ *      2. Reduce x to positive by (if x and y are unexceptional): 
+ *              ARG (x+iy) = arctan(y/x)           ... if x > 0,
+ *              ARG (x+iy) = pi - arctan[y/(-x)]   ... if x < 0,
+ *
+ * Special cases:
+ *
+ *      ATAN2((anything), NaN ) is NaN;
+ *      ATAN2(NAN , (anything) ) is NaN;
+ *      ATAN2(+-0, +(anything but NaN)) is +-0  ;
+ *      ATAN2(+-0, -(anything but NaN)) is +-pi ;
+ *      ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
+ *      ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
+ *      ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
+ *      ATAN2(+-INF,+INF ) is +-pi/4 ;
+ *      ATAN2(+-INF,-INF ) is +-3pi/4;
+ *      ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
+ *
+ * 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 <math.h>
+#include "math_private.h"
+
+static const double
+tiny  = 1.0e-300,
+zero  = 0.0,
+pi_o_4  = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */
+pi_o_2  = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */
+pi      = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */
+pi_lo   = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
+
+double
+atan2(double y, double x)
+{
+        double z;
+        int32_t k,m,hx,hy,ix,iy;
+        uint32_t lx,ly;
+
+        EXTRACT_WORDS(hx,lx,x);
+        ix = hx&0x7fffffff;
+        EXTRACT_WORDS(hy,ly,y);
+        iy = hy&0x7fffffff;
+        if(((ix|((lx|-lx)>>31))>0x7ff00000)||
+           ((iy|((ly|-ly)>>31))>0x7ff00000))    /* x or y is NaN */
+           return x+y;
+        if(((hx-0x3ff00000)|lx)==0) return atan(y);   /* x=1.0 */
+        m = ((hy>>31)&1)|((hx>>30)&2);  /* 2*sign(x)+sign(y) */
+
+    /* when y = 0 */
+        if((iy|ly)==0) {
+            switch(m) {
+                case 0: 
+                case 1: return y;       /* atan(+-0,+anything)=+-0 */
+                case 2: return  pi+tiny;/* atan(+0,-anything) = pi */
+                case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+            }
+        }
+    /* when x = 0 */
+        if((ix|lx)==0) return (hy<0)?  -pi_o_2-tiny: pi_o_2+tiny;
+            
+    /* when x is INF */
+        if(ix==0x7ff00000) {
+            if(iy==0x7ff00000) {
+                switch(m) {
+                    case 0: return  pi_o_4+tiny;/* atan(+INF,+INF) */
+                    case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+                    case 2: return  3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+                    case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+                }
+            } else {
+                switch(m) {
+                    case 0: return  zero  ;     /* atan(+...,+INF) */
+                    case 1: return -zero  ;     /* atan(-...,+INF) */
+                    case 2: return  pi+tiny  ;  /* atan(+...,-INF) */
+                    case 3: return -pi-tiny  ;  /* atan(-...,-INF) */
+                }
+            }
+        }
+    /* when y is INF */
+        if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+    /* compute y/x */
+        k = (iy-ix)>>20;
+        if(k > 60) z=pi_o_2+0.5*pi_lo;  /* |y/x| >  2**60 */
+        else if(hx<0&&k<-60) z=0.0;     /* |y|/x < -2**60 */
+        else z=atan(fabs(y/x));         /* safe to do y/x */
+        switch (m) {
+            case 0: return       z  ;   /* atan(+,+) */
+            case 1: {
+                      uint32_t zh;
+                      GET_HIGH_WORD(zh,z);
+                      SET_HIGH_WORD(z,zh ^ 0x80000000);
+                    }
+                    return       z  ;   /* atan(-,+) */
+            case 2: return  pi-(z-pi_lo);/* atan(+,-) */
+            default: /* case 3 */
+                    return  (z-pi_lo)-pi;/* atan(-,-) */
+        }
+}
diff --git a/src/math/e_atan2f.c b/src/math/e_atan2f.c
new file mode 100644
index 00000000..535e10a0
--- /dev/null
+++ b/src/math/e_atan2f.c
@@ -0,0 +1,93 @@
+/* e_atan2f.c -- float version of e_atan2.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 <math.h>
+#include "math_private.h"
+
+static const float
+tiny  = 1.0e-30,
+zero  = 0.0,
+pi_o_4  = 7.8539818525e-01, /* 0x3f490fdb */
+pi_o_2  = 1.5707963705e+00, /* 0x3fc90fdb */
+pi      = 3.1415927410e+00, /* 0x40490fdb */
+pi_lo   = -8.7422776573e-08; /* 0xb3bbbd2e */
+
+float
+atan2f(float y, float x)
+{
+        float z;
+        int32_t k,m,hx,hy,ix,iy;
+
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        GET_FLOAT_WORD(hy,y);
+        iy = hy&0x7fffffff;
+        if((ix>0x7f800000)||
+           (iy>0x7f800000))     /* x or y is NaN */
+           return x+y;
+        if(hx==0x3f800000) return atanf(y);   /* x=1.0 */
+        m = ((hy>>31)&1)|((hx>>30)&2);  /* 2*sign(x)+sign(y) */
+
+    /* when y = 0 */
+        if(iy==0) {
+            switch(m) {
+                case 0:
+                case 1: return y;       /* atan(+-0,+anything)=+-0 */
+                case 2: return  pi+tiny;/* atan(+0,-anything) = pi */
+                case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+            }
+        }
+    /* when x = 0 */
+        if(ix==0) return (hy<0)?  -pi_o_2-tiny: pi_o_2+tiny;
+
+    /* when x is INF */
+        if(ix==0x7f800000) {
+            if(iy==0x7f800000) {
+                switch(m) {
+                    case 0: return  pi_o_4+tiny;/* atan(+INF,+INF) */
+                    case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+                    case 2: return  (float)3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+                    case 3: return (float)-3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+                }
+            } else {
+                switch(m) {
+                    case 0: return  zero  ;     /* atan(+...,+INF) */
+                    case 1: return -zero  ;     /* atan(-...,+INF) */
+                    case 2: return  pi+tiny  ;  /* atan(+...,-INF) */
+                    case 3: return -pi-tiny  ;  /* atan(-...,-INF) */
+                }
+            }
+        }
+    /* when y is INF */
+        if(iy==0x7f800000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+    /* compute y/x */
+        k = (iy-ix)>>23;
+        if(k > 60) z=pi_o_2+(float)0.5*pi_lo;   /* |y/x| >  2**60 */
+        else if(hx<0&&k<-60) z=0.0;     /* |y|/x < -2**60 */
+        else z=atanf(fabsf(y/x));       /* safe to do y/x */
+        switch (m) {
+            case 0: return       z  ;   /* atan(+,+) */
+            case 1: {
+                      uint32_t zh;
+                      GET_FLOAT_WORD(zh,z);
+                      SET_FLOAT_WORD(z,zh ^ 0x80000000);
+                    }
+                    return       z  ;   /* atan(-,+) */
+            case 2: return  pi-(z-pi_lo);/* atan(+,-) */
+            default: /* case 3 */
+                    return  (z-pi_lo)-pi;/* atan(-,-) */
+        }
+}
diff --git a/src/math/e_atanh.c b/src/math/e_atanh.c
new file mode 100644
index 00000000..45f1c966
--- /dev/null
+++ b/src/math/e_atanh.c
@@ -0,0 +1,59 @@
+
+/* @(#)e_atanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* atanh(x)
+ * Method :
+ *    1.Reduced x to positive by atanh(-x) = -atanh(x)
+ *    2.For x>=0.5
+ *                  1              2x                          x
+ *      atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ *                  2             1 - x                      1 - x
+ *      
+ *      For x<0.5
+ *      atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ *      atanh(x) is NaN if |x| > 1 with signal;
+ *      atanh(NaN) is that NaN with no signal;
+ *      atanh(+-1) is +-INF with signal.
+ *
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one = 1.0, huge = 1e300;
+static const double zero = 0.0;
+
+double
+atanh(double x)
+{
+        double t;
+        int32_t hx,ix;
+        uint32_t lx;
+        EXTRACT_WORDS(hx,lx,x);
+        ix = hx&0x7fffffff;
+        if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */
+            return (x-x)/(x-x);
+        if(ix==0x3ff00000) 
+            return x/zero;
+        if(ix<0x3e300000&&(huge+x)>zero) return x;      /* x<2**-28 */
+        SET_HIGH_WORD(x,ix);
+        if(ix<0x3fe00000) {             /* x < 0.5 */
+            t = x+x;
+            t = 0.5*log1p(t+t*x/(one-x));
+        } else 
+            t = 0.5*log1p((x+x)/(one-x));
+        if(hx>=0) return t; else return -t;
+}
diff --git a/src/math/e_atanhf.c b/src/math/e_atanhf.c
new file mode 100644
index 00000000..7356cfc9
--- /dev/null
+++ b/src/math/e_atanhf.c
@@ -0,0 +1,42 @@
+/* e_atanhf.c -- float version of e_atanh.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 <math.h>
+#include "math_private.h"
+
+static const float one = 1.0, huge = 1e30;
+
+static const float zero = 0.0;
+
+float
+atanhf(float x)
+{
+        float t;
+        int32_t hx,ix;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if (ix>0x3f800000)              /* |x|>1 */
+            return (x-x)/(x-x);
+        if(ix==0x3f800000)
+            return x/zero;
+        if(ix<0x31800000&&(huge+x)>zero) return x;      /* x<2**-28 */
+        SET_FLOAT_WORD(x,ix);
+        if(ix<0x3f000000) {             /* x < 0.5 */
+            t = x+x;
+            t = (float)0.5*log1pf(t+t*x/(one-x));
+        } else
+            t = (float)0.5*log1pf((x+x)/(one-x));
+        if(hx>=0) return t; else return -t;
+}
diff --git a/src/math/e_cosh.c b/src/math/e_cosh.c
new file mode 100644
index 00000000..ad425bd3
--- /dev/null
+++ b/src/math/e_cosh.c
@@ -0,0 +1,82 @@
+
+/* @(#)e_cosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* cosh(x)
+ * Method : 
+ * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+ *      1. Replace x by |x| (cosh(x) = cosh(-x)). 
+ *      2. 
+ *                                                      [ exp(x) - 1 ]^2 
+ *          0        <= x <= ln2/2  :  cosh(x) := 1 + -------------------
+ *                                                         2*exp(x)
+ *
+ *                                                exp(x) +  1/exp(x)
+ *          ln2/2    <= x <= 22     :  cosh(x) := -------------------
+ *                                                        2
+ *          22       <= x <= lnovft :  cosh(x) := exp(x)/2 
+ *          lnovft   <= x <= ln2ovft:  cosh(x) := exp(x/2)/2 * exp(x/2)
+ *          ln2ovft  <  x           :  cosh(x) := huge*huge (overflow)
+ *
+ * Special cases:
+ *      cosh(x) is |x| if x is +INF, -INF, or NaN.
+ *      only cosh(0)=1 is exact for finite x.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one = 1.0, half=0.5, huge = 1.0e300;
+
+double
+cosh(double x)
+{
+        double t,w;
+        int32_t ix;
+        uint32_t lx;
+
+    /* High word of |x|. */
+        GET_HIGH_WORD(ix,x);
+        ix &= 0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7ff00000) return x*x;  
+
+    /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+        if(ix<0x3fd62e43) {
+            t = expm1(fabs(x));
+            w = one+t;
+            if (ix<0x3c800000) return w;        /* cosh(tiny) = 1 */
+            return one+(t*t)/(w+w);
+        }
+
+    /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+        if (ix < 0x40360000) {
+                t = exp(fabs(x));
+                return half*t+half/t;
+        }
+
+    /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+        if (ix < 0x40862E42)  return half*exp(fabs(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+        GET_LOW_WORD(lx,x);
+        if (ix<0x408633CE ||
+              ((ix==0x408633ce)&&(lx<=(uint32_t)0x8fb9f87d))) {
+            w = exp(half*fabs(x));
+            t = half*w;
+            return t*w;
+        }
+
+    /* |x| > overflowthresold, cosh(x) overflow */
+        return huge*huge;
+}
diff --git a/src/math/e_coshf.c b/src/math/e_coshf.c
new file mode 100644
index 00000000..6db10885
--- /dev/null
+++ b/src/math/e_coshf.c
@@ -0,0 +1,59 @@
+/* e_coshf.c -- float version of e_cosh.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 <math.h>
+#include "math_private.h"
+
+static const float one = 1.0, half=0.5, huge = 1.0e30;
+
+float
+coshf(float x)
+{
+        float t,w;
+        int32_t ix;
+
+        GET_FLOAT_WORD(ix,x);
+        ix &= 0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7f800000) return x*x;
+
+    /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+        if(ix<0x3eb17218) {
+            t = expm1f(fabsf(x));
+            w = one+t;
+            if (ix<0x24000000) return w;        /* cosh(tiny) = 1 */
+            return one+(t*t)/(w+w);
+        }
+
+    /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+        if (ix < 0x41b00000) {
+                t = expf(fabsf(x));
+                return half*t+half/t;
+        }
+
+    /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+        if (ix < 0x42b17180)  return half*expf(fabsf(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+        if (ix<=0x42b2d4fc) {
+            w = expf(half*fabsf(x));
+            t = half*w;
+            return t*w;
+        }
+
+    /* |x| > overflowthresold, cosh(x) overflow */
+        return huge*huge;
+}
diff --git a/src/math/e_exp.c b/src/math/e_exp.c
new file mode 100644
index 00000000..66107b95
--- /dev/null
+++ b/src/math/e_exp.c
@@ -0,0 +1,155 @@
+
+/* @(#)e_exp.c 1.6 04/04/22 */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* exp(x)
+ * Returns the exponential of x.
+ *
+ * Method
+ *   1. Argument reduction:
+ *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ *      Given x, find r and integer k such that
+ *
+ *               x = k*ln2 + r,  |r| <= 0.5*ln2.  
+ *
+ *      Here r will be represented as r = hi-lo for better 
+ *      accuracy.
+ *
+ *   2. Approximation of exp(r) by a special rational function on
+ *      the interval [0,0.34658]:
+ *      Write
+ *          R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ *      We use a special Remes algorithm on [0,0.34658] to generate 
+ *      a polynomial of degree 5 to approximate R. The maximum error 
+ *      of this polynomial approximation is bounded by 2**-59. In
+ *      other words,
+ *          R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ *      (where z=r*r, and the values of P1 to P5 are listed below)
+ *      and
+ *          |                  5          |     -59
+ *          | 2.0+P1*z+...+P5*z   -  R(z) | <= 2 
+ *          |                             |
+ *      The computation of exp(r) thus becomes
+ *                             2*r
+ *              exp(r) = 1 + -------
+ *                            R - r
+ *                                 r*R1(r)      
+ *                     = 1 + r + ----------- (for better accuracy)
+ *                                2 - R1(r)
+ *      where
+ *                               2       4             10
+ *              R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
+ *      
+ *   3. Scale back to obtain exp(x):
+ *      From step 1, we have
+ *         exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ *      exp(INF) is INF, exp(NaN) is NaN;
+ *      exp(-INF) is 0, and
+ *      for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ *      according to an error analysis, the error is always less than
+ *      1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ *      For IEEE double 
+ *          if x >  7.09782712893383973096e+02 then exp(x) overflow
+ *          if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * 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 <math.h>
+#include "math_private.h"
+
+static const double
+one     = 1.0,
+halF[2] = {0.5,-0.5,},
+huge    = 1.0e+300,
+twom1000= 9.33263618503218878990e-302,     /* 2**-1000=0x01700000,0*/
+o_threshold=  7.09782712893383973096e+02,  /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02,  /* 0xc0874910, 0xD52D3051 */
+ln2HI[2]   ={ 6.93147180369123816490e-01,  /* 0x3fe62e42, 0xfee00000 */
+             -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */
+ln2LO[2]   ={ 1.90821492927058770002e-10,  /* 0x3dea39ef, 0x35793c76 */
+             -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */
+invln2 =  1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
+P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5   =  4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
+
+
+double
+exp(double x) /* default IEEE double exp */
+{
+        double y,hi=0.0,lo=0.0,c,t;
+        int32_t k=0,xsb;
+        uint32_t hx;
+
+        GET_HIGH_WORD(hx,x);
+        xsb = (hx>>31)&1;               /* sign bit of x */
+        hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out non-finite argument */
+        if(hx >= 0x40862E42) {                  /* if |x|>=709.78... */
+            if(hx>=0x7ff00000) {
+                uint32_t lx;
+                GET_LOW_WORD(lx,x);
+                if(((hx&0xfffff)|lx)!=0)
+                     return x+x;                /* NaN */
+                else return (xsb==0)? x:0.0;    /* exp(+-inf)={inf,0} */
+            }
+            if(x > o_threshold) return huge*huge; /* overflow */
+            if(x < u_threshold) return twom1000*twom1000; /* underflow */
+        }
+
+    /* argument reduction */
+        if(hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */ 
+            if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+                hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+            } else {
+                k  = (int)(invln2*x+halF[xsb]);
+                t  = k;
+                hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+                lo = t*ln2LO[0];
+            }
+            x  = hi - lo;
+        } 
+        else if(hx < 0x3e300000)  {     /* when |x|<2**-28 */
+            if(huge+x>one) return one+x;/* trigger inexact */
+        }
+        else k = 0;
+
+    /* x is now in primary range */
+        t  = x*x;
+        c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+        if(k==0)        return one-((x*c)/(c-2.0)-x); 
+        else            y = one-((lo-(x*c)/(2.0-c))-hi);
+        if(k >= -1021) {
+            uint32_t hy;
+            GET_HIGH_WORD(hy,y);
+            SET_HIGH_WORD(y,hy+(k<<20));        /* add k to y's exponent */
+            return y;
+        } else {
+            uint32_t hy;
+            GET_HIGH_WORD(hy,y);
+            SET_HIGH_WORD(y,hy+((k+1000)<<20)); /* add k to y's exponent */
+            return y*twom1000;
+        }
+}
diff --git a/src/math/e_expf.c b/src/math/e_expf.c
new file mode 100644
index 00000000..99818edc
--- /dev/null
+++ b/src/math/e_expf.c
@@ -0,0 +1,91 @@
+/* e_expf.c -- float version of e_exp.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 <math.h>
+#include "math_private.h"
+
+static const float
+one     = 1.0,
+halF[2] = {0.5,-0.5,},
+huge    = 1.0e+30,
+twom100 = 7.8886090522e-31,      /* 2**-100=0x0d800000 */
+o_threshold=  8.8721679688e+01,  /* 0x42b17180 */
+u_threshold= -1.0397208405e+02,  /* 0xc2cff1b5 */
+ln2HI[2]   ={ 6.9313812256e-01,         /* 0x3f317180 */
+             -6.9313812256e-01,},       /* 0xbf317180 */
+ln2LO[2]   ={ 9.0580006145e-06,         /* 0x3717f7d1 */
+             -9.0580006145e-06,},       /* 0xb717f7d1 */
+invln2 =  1.4426950216e+00,             /* 0x3fb8aa3b */
+P1   =  1.6666667163e-01, /* 0x3e2aaaab */
+P2   = -2.7777778450e-03, /* 0xbb360b61 */
+P3   =  6.6137559770e-05, /* 0x388ab355 */
+P4   = -1.6533901999e-06, /* 0xb5ddea0e */
+P5   =  4.1381369442e-08; /* 0x3331bb4c */
+
+float
+expf(float x) /* default IEEE double exp */
+{
+        float y,hi=0.0,lo=0.0,c,t;
+        int32_t k=0,xsb;
+        uint32_t hx;
+
+        GET_FLOAT_WORD(hx,x);
+        xsb = (hx>>31)&1;               /* sign bit of x */
+        hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out non-finite argument */
+        if(hx >= 0x42b17218) {                  /* if |x|>=88.721... */
+            if(hx>0x7f800000)
+                 return x+x;                    /* NaN */
+            if(hx==0x7f800000)
+                return (xsb==0)? x:0.0;         /* exp(+-inf)={inf,0} */
+            if(x > o_threshold) return huge*huge; /* overflow */
+            if(x < u_threshold) return twom100*twom100; /* underflow */
+        }
+
+    /* argument reduction */
+        if(hx > 0x3eb17218) {           /* if  |x| > 0.5 ln2 */
+            if(hx < 0x3F851592) {       /* and |x| < 1.5 ln2 */
+                hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+            } else {
+                k  = invln2*x+halF[xsb];
+                t  = k;
+                hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+                lo = t*ln2LO[0];
+            }
+            x  = hi - lo;
+        }
+        else if(hx < 0x31800000)  {     /* when |x|<2**-28 */
+            if(huge+x>one) return one+x;/* trigger inexact */
+        }
+        else k = 0;
+
+    /* x is now in primary range */
+        t  = x*x;
+        c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+        if(k==0)        return one-((x*c)/(c-(float)2.0)-x);
+        else            y = one-((lo-(x*c)/((float)2.0-c))-hi);
+        if(k >= -125) {
+            uint32_t hy;
+            GET_FLOAT_WORD(hy,y);
+            SET_FLOAT_WORD(y,hy+(k<<23));       /* add k to y's exponent */
+            return y;
+        } else {
+            uint32_t hy;
+            GET_FLOAT_WORD(hy,y);
+            SET_FLOAT_WORD(y,hy+((k+100)<<23)); /* add k to y's exponent */
+            return y*twom100;
+        }
+}
diff --git a/src/math/e_fmod.c b/src/math/e_fmod.c
new file mode 100644
index 00000000..99afe489
--- /dev/null
+++ b/src/math/e_fmod.c
@@ -0,0 +1,129 @@
+
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* 
+ * fmod(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one = 1.0, Zero[] = {0.0, -0.0,};
+
+double
+fmod(double x, double y)
+{
+        int32_t n,hx,hy,hz,ix,iy,sx,i;
+        uint32_t lx,ly,lz;
+
+        EXTRACT_WORDS(hx,lx,x);
+        EXTRACT_WORDS(hy,ly,y);
+        sx = hx&0x80000000;             /* sign of x */
+        hx ^=sx;                /* |x| */
+        hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+        if((hy|ly)==0||(hx>=0x7ff00000)||       /* y=0,or x not finite */
+          ((hy|((ly|-ly)>>31))>0x7ff00000))     /* or y is NaN */
+            return (x*y)/(x*y);
+        if(hx<=hy) {
+            if((hx<hy)||(lx<ly)) return x;      /* |x|<|y| return x */
+            if(lx==ly) 
+                return Zero[(uint32_t)sx>>31]; /* |x|=|y| return x*0*/
+        }
+
+    /* determine ix = ilogb(x) */
+        if(hx<0x00100000) {     /* subnormal x */
+            if(hx==0) {
+                for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+            } else {
+                for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+            }
+        } else ix = (hx>>20)-1023;
+
+    /* determine iy = ilogb(y) */
+        if(hy<0x00100000) {     /* subnormal y */
+            if(hy==0) {
+                for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+            } else {
+                for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+            }
+        } else iy = (hy>>20)-1023;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+        if(ix >= -1022) 
+            hx = 0x00100000|(0x000fffff&hx);
+        else {          /* subnormal x, shift x to normal */
+            n = -1022-ix;
+            if(n<=31) {
+                hx = (hx<<n)|(lx>>(32-n));
+                lx <<= n;
+            } else {
+                hx = lx<<(n-32);
+                lx = 0;
+            }
+        }
+        if(iy >= -1022) 
+            hy = 0x00100000|(0x000fffff&hy);
+        else {          /* subnormal y, shift y to normal */
+            n = -1022-iy;
+            if(n<=31) {
+                hy = (hy<<n)|(ly>>(32-n));
+                ly <<= n;
+            } else {
+                hy = ly<<(n-32);
+                ly = 0;
+            }
+        }
+
+    /* fix point fmod */
+        n = ix - iy;
+        while(n--) {
+            hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+            if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+            else {
+                if((hz|lz)==0)          /* return sign(x)*0 */
+                    return Zero[(uint32_t)sx>>31];
+                hx = hz+hz+(lz>>31); lx = lz+lz;
+            }
+        }
+        hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+        if(hz>=0) {hx=hz;lx=lz;}
+
+    /* convert back to floating value and restore the sign */
+        if((hx|lx)==0)                  /* return sign(x)*0 */
+            return Zero[(uint32_t)sx>>31];
+        while(hx<0x00100000) {          /* normalize x */
+            hx = hx+hx+(lx>>31); lx = lx+lx;
+            iy -= 1;
+        }
+        if(iy>= -1022) {        /* normalize output */
+            hx = ((hx-0x00100000)|((iy+1023)<<20));
+            INSERT_WORDS(x,hx|sx,lx);
+        } else {                /* subnormal output */
+            n = -1022 - iy;
+            if(n<=20) {
+                lx = (lx>>n)|((uint32_t)hx<<(32-n));
+                hx >>= n;
+            } else if (n<=31) {
+                lx = (hx<<(32-n))|(lx>>n); hx = sx;
+            } else {
+                lx = hx>>(n-32); hx = sx;
+            }
+            INSERT_WORDS(x,hx|sx,lx);
+            x *= one;           /* create necessary signal */
+        }
+        return x;               /* exact output */
+}
diff --git a/src/math/e_fmodf.c b/src/math/e_fmodf.c
new file mode 100644
index 00000000..fe86cb04
--- /dev/null
+++ b/src/math/e_fmodf.c
@@ -0,0 +1,101 @@
+/* e_fmodf.c -- float version of e_fmod.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.
+ * ====================================================
+ */
+
+/*
+ * fmodf(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float one = 1.0, Zero[] = {0.0, -0.0,};
+
+float
+fmodf(float x, float y)
+{
+        int32_t n,hx,hy,hz,ix,iy,sx,i;
+
+        GET_FLOAT_WORD(hx,x);
+        GET_FLOAT_WORD(hy,y);
+        sx = hx&0x80000000;             /* sign of x */
+        hx ^=sx;                /* |x| */
+        hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+        if(hy==0||(hx>=0x7f800000)||            /* y=0,or x not finite */
+           (hy>0x7f800000))                     /* or y is NaN */
+            return (x*y)/(x*y);
+        if(hx<hy) return x;                     /* |x|<|y| return x */
+        if(hx==hy)
+            return Zero[(uint32_t)sx>>31];     /* |x|=|y| return x*0*/
+
+    /* determine ix = ilogb(x) */
+        if(hx<0x00800000) {     /* subnormal x */
+            for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1;
+        } else ix = (hx>>23)-127;
+
+    /* determine iy = ilogb(y) */
+        if(hy<0x00800000) {     /* subnormal y */
+            for (iy = -126,i=(hy<<8); i>=0; i<<=1) iy -=1;
+        } else iy = (hy>>23)-127;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+        if(ix >= -126)
+            hx = 0x00800000|(0x007fffff&hx);
+        else {          /* subnormal x, shift x to normal */
+            n = -126-ix;
+            hx = hx<<n;
+        }
+        if(iy >= -126)
+            hy = 0x00800000|(0x007fffff&hy);
+        else {          /* subnormal y, shift y to normal */
+            n = -126-iy;
+            hy = hy<<n;
+        }
+
+    /* fix point fmod */
+        n = ix - iy;
+        while(n--) {
+            hz=hx-hy;
+            if(hz<0){hx = hx+hx;}
+            else {
+                if(hz==0)               /* return sign(x)*0 */
+                    return Zero[(uint32_t)sx>>31];
+                hx = hz+hz;
+            }
+        }
+        hz=hx-hy;
+        if(hz>=0) {hx=hz;}
+
+    /* convert back to floating value and restore the sign */
+        if(hx==0)                       /* return sign(x)*0 */
+            return Zero[(uint32_t)sx>>31];
+        while(hx<0x00800000) {          /* normalize x */
+            hx = hx+hx;
+            iy -= 1;
+        }
+        if(iy>= -126) {         /* normalize output */
+            hx = ((hx-0x00800000)|((iy+127)<<23));
+            SET_FLOAT_WORD(x,hx|sx);
+        } else {                /* subnormal output */
+            n = -126 - iy;
+            hx >>= n;
+            SET_FLOAT_WORD(x,hx|sx);
+            x *= one;           /* create necessary signal */
+        }
+        return x;               /* exact output */
+}
diff --git a/src/math/e_hypot.c b/src/math/e_hypot.c
new file mode 100644
index 00000000..e925adc3
--- /dev/null
+++ b/src/math/e_hypot.c
@@ -0,0 +1,121 @@
+
+/* @(#)e_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* hypot(x,y)
+ *
+ * Method :                  
+ *      If (assume round-to-nearest) z=x*x+y*y 
+ *      has error less than sqrt(2)/2 ulp, than 
+ *      sqrt(z) has error less than 1 ulp (exercise).
+ *
+ *      So, compute sqrt(x*x+y*y) with some care as 
+ *      follows to get the error below 1 ulp:
+ *
+ *      Assume x>y>0;
+ *      (if possible, set rounding to round-to-nearest)
+ *      1. if x > 2y  use
+ *              x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ *      where x1 = x with lower 32 bits cleared, x2 = x-x1; else
+ *      2. if x <= 2y use
+ *              t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
+ *      where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1, 
+ *      y1= y with lower 32 bits chopped, y2 = y-y1.
+ *              
+ *      NOTE: scaling may be necessary if some argument is too 
+ *            large or too tiny
+ *
+ * Special cases:
+ *      hypot(x,y) is INF if x or y is +INF or -INF; else
+ *      hypot(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ *      hypot(x,y) returns sqrt(x^2+y^2) with error less 
+ *      than 1 ulps (units in the last place) 
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+hypot(double x, double y)
+{
+        double a=x,b=y,t1,t2,y1,y2,w;
+        int32_t j,k,ha,hb;
+
+        GET_HIGH_WORD(ha,x);
+        ha &= 0x7fffffff;
+        GET_HIGH_WORD(hb,y);
+        hb &= 0x7fffffff;
+        if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+        SET_HIGH_WORD(a,ha);    /* a <- |a| */
+        SET_HIGH_WORD(b,hb);    /* b <- |b| */
+        if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
+        k=0;
+        if(ha > 0x5f300000) {   /* a>2**500 */
+           if(ha >= 0x7ff00000) {       /* Inf or NaN */
+               uint32_t low;
+               w = a+b;                 /* for sNaN */
+               GET_LOW_WORD(low,a);
+               if(((ha&0xfffff)|low)==0) w = a;
+               GET_LOW_WORD(low,b);
+               if(((hb^0x7ff00000)|low)==0) w = b;
+               return w;
+           }
+           /* scale a and b by 2**-600 */
+           ha -= 0x25800000; hb -= 0x25800000;  k += 600;
+           SET_HIGH_WORD(a,ha);
+           SET_HIGH_WORD(b,hb);
+        }
+        if(hb < 0x20b00000) {   /* b < 2**-500 */
+            if(hb <= 0x000fffff) {      /* subnormal b or 0 */
+                uint32_t low;
+                GET_LOW_WORD(low,b);
+                if((hb|low)==0) return a;
+                t1=0;
+                SET_HIGH_WORD(t1,0x7fd00000);   /* t1=2^1022 */
+                b *= t1;
+                a *= t1;
+                k -= 1022;
+            } else {            /* scale a and b by 2^600 */
+                ha += 0x25800000;       /* a *= 2^600 */
+                hb += 0x25800000;       /* b *= 2^600 */
+                k -= 600;
+                SET_HIGH_WORD(a,ha);
+                SET_HIGH_WORD(b,hb);
+            }
+        }
+    /* medium size a and b */
+        w = a-b;
+        if (w>b) {
+            t1 = 0;
+            SET_HIGH_WORD(t1,ha);
+            t2 = a-t1;
+            w  = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
+        } else {
+            a  = a+a;
+            y1 = 0;
+            SET_HIGH_WORD(y1,hb);
+            y2 = b - y1;
+            t1 = 0;
+            SET_HIGH_WORD(t1,ha+0x00100000);
+            t2 = a - t1;
+            w  = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+        }
+        if(k!=0) {
+            uint32_t high;
+            t1 = 1.0;
+            GET_HIGH_WORD(high,t1);
+            SET_HIGH_WORD(t1,high+(k<<20));
+            return t1*w;
+        } else return w;
+}
diff --git a/src/math/e_hypotf.c b/src/math/e_hypotf.c
new file mode 100644
index 00000000..13773554
--- /dev/null
+++ b/src/math/e_hypotf.c
@@ -0,0 +1,79 @@
+/* e_hypotf.c -- float version of e_hypot.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 <math.h>
+#include "math_private.h"
+
+float
+hypotf(float x, float y)
+{
+        float a=x,b=y,t1,t2,y1,y2,w;
+        int32_t j,k,ha,hb;
+
+        GET_FLOAT_WORD(ha,x);
+        ha &= 0x7fffffff;
+        GET_FLOAT_WORD(hb,y);
+        hb &= 0x7fffffff;
+        if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+        SET_FLOAT_WORD(a,ha);   /* a <- |a| */
+        SET_FLOAT_WORD(b,hb);   /* b <- |b| */
+        if((ha-hb)>0xf000000) {return a+b;} /* x/y > 2**30 */
+        k=0;
+        if(ha > 0x58800000) {   /* a>2**50 */
+           if(ha >= 0x7f800000) {       /* Inf or NaN */
+               w = a+b;                 /* for sNaN */
+               if(ha == 0x7f800000) w = a;
+               if(hb == 0x7f800000) w = b;
+               return w;
+           }
+           /* scale a and b by 2**-68 */
+           ha -= 0x22000000; hb -= 0x22000000;  k += 68;
+           SET_FLOAT_WORD(a,ha);
+           SET_FLOAT_WORD(b,hb);
+        }
+        if(hb < 0x26800000) {   /* b < 2**-50 */
+            if(hb <= 0x007fffff) {      /* subnormal b or 0 */
+                if(hb==0) return a;
+                SET_FLOAT_WORD(t1,0x7e800000);  /* t1=2^126 */
+                b *= t1;
+                a *= t1;
+                k -= 126;
+            } else {            /* scale a and b by 2^68 */
+                ha += 0x22000000;       /* a *= 2^68 */
+                hb += 0x22000000;       /* b *= 2^68 */
+                k -= 68;
+                SET_FLOAT_WORD(a,ha);
+                SET_FLOAT_WORD(b,hb);
+            }
+        }
+    /* medium size a and b */
+        w = a-b;
+        if (w>b) {
+            SET_FLOAT_WORD(t1,ha&0xfffff000);
+            t2 = a-t1;
+            w  = sqrtf(t1*t1-(b*(-b)-t2*(a+t1)));
+        } else {
+            a  = a+a;
+            SET_FLOAT_WORD(y1,hb&0xfffff000);
+            y2 = b - y1;
+            SET_FLOAT_WORD(t1,ha+0x00800000);
+            t2 = a - t1;
+            w  = sqrtf(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+        }
+        if(k!=0) {
+            SET_FLOAT_WORD(t1,0x3f800000+(k<<23));
+            return t1*w;
+        } else return w;
+}
diff --git a/src/math/e_log.c b/src/math/e_log.c
new file mode 100644
index 00000000..9eb0e444
--- /dev/null
+++ b/src/math/e_log.c
@@ -0,0 +1,131 @@
+
+/* @(#)e_log.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* log(x)
+ * Return the logrithm of x
+ *
+ * Method :                  
+ *   1. Argument Reduction: find k and f such that 
+ *                      x = 2^k * (1+f), 
+ *         where  sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ *   2. Approximation of log(1+f).
+ *      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ *               = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ *               = 2s + s*R
+ *      We use a special Reme algorithm on [0,0.1716] to generate 
+ *      a polynomial of degree 14 to approximate R The maximum error 
+ *      of this polynomial approximation is bounded by 2**-58.45. In
+ *      other words,
+ *                      2      4      6      8      10      12      14
+ *          R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s  +Lg6*s  +Lg7*s
+ *      (the values of Lg1 to Lg7 are listed in the program)
+ *      and
+ *          |      2          14          |     -58.45
+ *          | Lg1*s +...+Lg7*s    -  R(z) | <= 2 
+ *          |                             |
+ *      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ *      In order to guarantee error in log below 1ulp, we compute log
+ *      by
+ *              log(1+f) = f - s*(f - R)        (if f is not too large)
+ *              log(1+f) = f - (hfsq - s*(hfsq+R)).     (better accuracy)
+ *      
+ *      3. Finally,  log(x) = k*ln2 + log(1+f).  
+ *                          = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ *         Here ln2 is split into two floating point number: 
+ *                      ln2_hi + ln2_lo,
+ *         where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * 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.
+ *
+ * Accuracy:
+ *      according to an error analysis, the error is always less than
+ *      1 ulp (unit in the last place).
+ *
+ * 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 <math.h>
+#include "math_private.h"
+
+static const double
+ln2_hi  =  6.93147180369123816490e-01,  /* 3fe62e42 fee00000 */
+ln2_lo  =  1.90821492927058770002e-10,  /* 3dea39ef 35793c76 */
+two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */
+Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
+
+static const double zero   =  0.0;
+
+double
+log(double x)
+{
+        double hfsq,f,s,z,R,w,t1,t2,dk;
+        int32_t k,hx,i,j;
+        uint32_t lx;
+
+        EXTRACT_WORDS(hx,lx,x);
+
+        k=0;
+        if (hx < 0x00100000) {                  /* x < 2**-1022  */
+            if (((hx&0x7fffffff)|lx)==0) 
+                return -two54/zero;             /* log(+-0)=-inf */
+            if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+            k -= 54; x *= two54; /* subnormal number, scale up x */
+            GET_HIGH_WORD(hx,x);
+        } 
+        if (hx >= 0x7ff00000) return x+x;
+        k += (hx>>20)-1023;
+        hx &= 0x000fffff;
+        i = (hx+0x95f64)&0x100000;
+        SET_HIGH_WORD(x,hx|(i^0x3ff00000));     /* normalize x or x/2 */
+        k += (i>>20);
+        f = x-1.0;
+        if((0x000fffff&(2+hx))<3) {     /* |f| < 2**-20 */
+            if(f==zero) { if(k==0) return zero;  else {dk=(double)k;
+                                 return dk*ln2_hi+dk*ln2_lo;} }
+            R = f*f*(0.5-0.33333333333333333*f);
+            if(k==0) return f-R; else {dk=(double)k;
+                     return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+        }
+        s = f/(2.0+f); 
+        dk = (double)k;
+        z = s*s;
+        i = hx-0x6147a;
+        w = z*z;
+        j = 0x6b851-hx;
+        t1= w*(Lg2+w*(Lg4+w*Lg6)); 
+        t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); 
+        i |= j;
+        R = t2+t1;
+        if(i>0) {
+            hfsq=0.5*f*f;
+            if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                     return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+        } else {
+            if(k==0) return f-s*(f-R); else
+                     return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+        }
+}
diff --git a/src/math/e_log10.c b/src/math/e_log10.c
new file mode 100644
index 00000000..3be179f7
--- /dev/null
+++ b/src/math/e_log10.c
@@ -0,0 +1,83 @@
+
+/* @(#)e_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* log10(x)
+ * Return the base 10 logarithm of x
+ * 
+ * Method :
+ *      Let log10_2hi = leading 40 bits of log10(2) and
+ *          log10_2lo = log10(2) - log10_2hi,
+ *          ivln10   = 1/log(10) rounded.
+ *      Then
+ *              n = ilogb(x), 
+ *              if(n<0)  n = n+1;
+ *              x = scalbn(x,-n);
+ *              log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
+ *
+ * Note 1:
+ *      To guarantee log10(10**n)=n, where 10**n is normal, the rounding 
+ *      mode must set to Round-to-Nearest.
+ * Note 2:
+ *      [1/log(10)] rounded to 53 bits has error  .198   ulps;
+ *      log10 is monotonic at all binary break points.
+ *
+ * Special cases:
+ *      log10(x) is NaN with signal if x < 0; 
+ *      log10(+INF) is +INF with no signal; log10(0) is -INF with signal;
+ *      log10(NaN) is that NaN with no signal;
+ *      log10(10**N) = N  for N=0,1,...,22.
+ *
+ * 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 <math.h>
+#include "math_private.h"
+
+static const double
+two54      =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+ivln10     =  4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */
+log10_2hi  =  3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
+log10_2lo  =  3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
+
+static const double zero   =  0.0;
+
+double
+log10(double x)
+{
+        double y,z;
+        int32_t i,k,hx;
+        uint32_t lx;
+
+        EXTRACT_WORDS(hx,lx,x);
+
+        k=0;
+        if (hx < 0x00100000) {                  /* x < 2**-1022  */
+            if (((hx&0x7fffffff)|lx)==0)
+                return -two54/zero;             /* log(+-0)=-inf */
+            if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+            k -= 54; x *= two54; /* subnormal number, scale up x */
+            GET_HIGH_WORD(hx,x);
+        }
+        if (hx >= 0x7ff00000) return x+x;
+        k += (hx>>20)-1023;
+        i  = ((uint32_t)k&0x80000000)>>31;
+        hx = (hx&0x000fffff)|((0x3ff-i)<<20);
+        y  = (double)(k+i);
+        SET_HIGH_WORD(x,hx);
+        z  = y*log10_2lo + ivln10*log(x);
+        return  z+y*log10_2hi;
+}
diff --git a/src/math/e_log10f.c b/src/math/e_log10f.c
new file mode 100644
index 00000000..8fc5c5ca
--- /dev/null
+++ b/src/math/e_log10f.c
@@ -0,0 +1,51 @@
+/* e_log10f.c -- float version of e_log10.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 <math.h>
+#include "math_private.h"
+
+static const float
+two25      =  3.3554432000e+07, /* 0x4c000000 */
+ivln10     =  4.3429449201e-01, /* 0x3ede5bd9 */
+log10_2hi  =  3.0102920532e-01, /* 0x3e9a2080 */
+log10_2lo  =  7.9034151668e-07; /* 0x355427db */
+
+static const float zero   =  0.0;
+
+float
+log10f(float x)
+{
+        float y,z;
+        int32_t i,k,hx;
+
+        GET_FLOAT_WORD(hx,x);
+
+        k=0;
+        if (hx < 0x00800000) {                  /* x < 2**-126  */
+            if ((hx&0x7fffffff)==0)
+                return -two25/zero;             /* log(+-0)=-inf */
+            if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+            k -= 25; x *= two25; /* subnormal number, scale up x */
+            GET_FLOAT_WORD(hx,x);
+        }
+        if (hx >= 0x7f800000) return x+x;
+        k += (hx>>23)-127;
+        i  = ((uint32_t)k&0x80000000)>>31;
+        hx = (hx&0x007fffff)|((0x7f-i)<<23);
+        y  = (float)(k+i);
+        SET_FLOAT_WORD(x,hx);
+        z  = y*log10_2lo + ivln10*logf(x);
+        return  z+y*log10_2hi;
+}
diff --git a/src/math/e_logf.c b/src/math/e_logf.c
new file mode 100644
index 00000000..46a8b8ce
--- /dev/null
+++ b/src/math/e_logf.c
@@ -0,0 +1,81 @@
+/* e_logf.c -- float version of e_log.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 <math.h>
+#include "math_private.h"
+
+static const float
+ln2_hi =   6.9313812256e-01,    /* 0x3f317180 */
+ln2_lo =   9.0580006145e-06,    /* 0x3717f7d1 */
+two25 =    3.355443200e+07,     /* 0x4c000000 */
+Lg1 = 6.6666668653e-01, /* 3F2AAAAB */
+Lg2 = 4.0000000596e-01, /* 3ECCCCCD */
+Lg3 = 2.8571429849e-01, /* 3E924925 */
+Lg4 = 2.2222198546e-01, /* 3E638E29 */
+Lg5 = 1.8183572590e-01, /* 3E3A3325 */
+Lg6 = 1.5313838422e-01, /* 3E1CD04F */
+Lg7 = 1.4798198640e-01; /* 3E178897 */
+
+static const float zero   =  0.0;
+
+float
+logf(float x)
+{
+        float hfsq,f,s,z,R,w,t1,t2,dk;
+        int32_t k,ix,i,j;
+
+        GET_FLOAT_WORD(ix,x);
+
+        k=0;
+        if (ix < 0x00800000) {                  /* x < 2**-126  */
+            if ((ix&0x7fffffff)==0)
+                return -two25/zero;             /* log(+-0)=-inf */
+            if (ix<0) return (x-x)/zero;        /* log(-#) = NaN */
+            k -= 25; x *= two25; /* subnormal number, scale up x */
+            GET_FLOAT_WORD(ix,x);
+        }
+        if (ix >= 0x7f800000) return x+x;
+        k += (ix>>23)-127;
+        ix &= 0x007fffff;
+        i = (ix+(0x95f64<<3))&0x800000;
+        SET_FLOAT_WORD(x,ix|(i^0x3f800000));    /* normalize x or x/2 */
+        k += (i>>23);
+        f = x-(float)1.0;
+        if((0x007fffff&(15+ix))<16) {   /* |f| < 2**-20 */
+            if(f==zero) { if(k==0) return zero;  else {dk=(float)k;
+                                 return dk*ln2_hi+dk*ln2_lo;} }
+            R = f*f*((float)0.5-(float)0.33333333333333333*f);
+            if(k==0) return f-R; else {dk=(float)k;
+                     return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+        }
+        s = f/((float)2.0+f);
+        dk = (float)k;
+        z = s*s;
+        i = ix-(0x6147a<<3);
+        w = z*z;
+        j = (0x6b851<<3)-ix;
+        t1= w*(Lg2+w*(Lg4+w*Lg6));
+        t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+        i |= j;
+        R = t2+t1;
+        if(i>0) {
+            hfsq=(float)0.5*f*f;
+            if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                     return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+        } else {
+            if(k==0) return f-s*(f-R); else
+                     return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+        }
+}
diff --git a/src/math/e_pow.c b/src/math/e_pow.c
new file mode 100644
index 00000000..aad24287
--- /dev/null
+++ b/src/math/e_pow.c
@@ -0,0 +1,300 @@
+/* @(#)e_pow.c 1.5 04/04/22 SMI */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* pow(x,y) return x**y
+ *
+ *                    n
+ * Method:  Let x =  2   * (1+f)
+ *      1. Compute and return log2(x) in two pieces:
+ *              log2(x) = w1 + w2,
+ *         where w1 has 53-24 = 29 bit trailing zeros.
+ *      2. Perform y*log2(x) = n+y' by simulating muti-precision 
+ *         arithmetic, where |y'|<=0.5.
+ *      3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ *      1.  (anything) ** 0  is 1
+ *      2.  (anything) ** 1  is itself
+ *      3.  (anything) ** NAN is NAN
+ *      4.  NAN ** (anything except 0) is NAN
+ *      5.  +-(|x| > 1) **  +INF is +INF
+ *      6.  +-(|x| > 1) **  -INF is +0
+ *      7.  +-(|x| < 1) **  +INF is +0
+ *      8.  +-(|x| < 1) **  -INF is +INF
+ *      9.  +-1         ** +-INF is NAN
+ *      10. +0 ** (+anything except 0, NAN)               is +0
+ *      11. -0 ** (+anything except 0, NAN, odd integer)  is +0
+ *      12. +0 ** (-anything except 0, NAN)               is +INF
+ *      13. -0 ** (-anything except 0, NAN, odd integer)  is +INF
+ *      14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ *      15. +INF ** (+anything except 0,NAN) is +INF
+ *      16. +INF ** (-anything except 0,NAN) is +0
+ *      17. -INF ** (anything)  = -0 ** (-anything)
+ *      18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ *      19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ *      pow(x,y) returns x**y nearly rounded. In particular
+ *                      pow(integer,integer)
+ *      always returns the correct integer provided it is 
+ *      representable.
+ *
+ * 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 <math.h>
+#include "math_private.h"
+
+static const double
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero    =  0.0,
+one     =  1.0,
+two     =  2.0,
+two53   =  9007199254740992.0,  /* 0x43400000, 0x00000000 */
+huge    =  1.0e300,
+tiny    =  1.0e-300,
+        /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1  =  5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2  =  4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3  =  3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4  =  2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5  =  2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6  =  2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5   =  4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2  =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h  =  6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l  = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt =  8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp    =  9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h  =  9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l  = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2    =  1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h  =  1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l  =  1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+double
+pow(double x, double y)
+{
+        double z,ax,z_h,z_l,p_h,p_l;
+        double y1,t1,t2,r,s,t,u,v,w;
+        int32_t i,j,k,yisint,n;
+        int32_t hx,hy,ix,iy;
+        uint32_t lx,ly;
+
+        EXTRACT_WORDS(hx,lx,x);
+        EXTRACT_WORDS(hy,ly,y);
+        ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
+
+    /* y==zero: x**0 = 1 */
+        if((iy|ly)==0) return one;      
+
+    /* +-NaN return x+y */
+        if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+           iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) 
+                return x+y;     
+
+    /* determine if y is an odd int when x < 0
+     * yisint = 0       ... y is not an integer
+     * yisint = 1       ... y is an odd int
+     * yisint = 2       ... y is an even int
+     */
+        yisint  = 0;
+        if(hx<0) {      
+            if(iy>=0x43400000) yisint = 2; /* even integer y */
+            else if(iy>=0x3ff00000) {
+                k = (iy>>20)-0x3ff;        /* exponent */
+                if(k>20) {
+                    j = ly>>(52-k);
+                    if((j<<(52-k))==ly) yisint = 2-(j&1);
+                } else if(ly==0) {
+                    j = iy>>(20-k);
+                    if((j<<(20-k))==iy) yisint = 2-(j&1);
+                }
+            }           
+        } 
+
+    /* special value of y */
+        if(ly==0) {     
+            if (iy==0x7ff00000) {       /* y is +-inf */
+                if(((ix-0x3ff00000)|lx)==0)
+                    return  y - y;      /* inf**+-1 is NaN */
+                else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+                    return (hy>=0)? y: zero;
+                else                    /* (|x|<1)**-,+inf = inf,0 */
+                    return (hy<0)?-y: zero;
+            } 
+            if(iy==0x3ff00000) {        /* y is  +-1 */
+                if(hy<0) return one/x; else return x;
+            }
+            if(hy==0x40000000) return x*x; /* y is  2 */
+            if(hy==0x3fe00000) {        /* y is  0.5 */
+                if(hx>=0)       /* x >= +0 */
+                return sqrt(x); 
+            }
+        }
+
+        ax   = fabs(x);
+    /* special value of x */
+        if(lx==0) {
+            if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+                z = ax;                 /*x is +-0,+-inf,+-1*/
+                if(hy<0) z = one/z;     /* z = (1/|x|) */
+                if(hx<0) {
+                    if(((ix-0x3ff00000)|yisint)==0) {
+                        z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+                    } else if(yisint==1) 
+                        z = -z;         /* (x<0)**odd = -(|x|**odd) */
+                }
+                return z;
+            }
+        }
+    
+    /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be
+        n = (hx>>31)+1;
+       but ANSI C says a right shift of a signed negative quantity is
+       implementation defined.  */
+        n = ((uint32_t)hx>>31)-1;
+
+    /* (x<0)**(non-int) is NaN */
+        if((n|yisint)==0) return (x-x)/(x-x);
+
+        s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+        if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+    /* |y| is huge */
+        if(iy>0x41e00000) { /* if |y| > 2**31 */
+            if(iy>0x43f00000){  /* if |y| > 2**64, must o/uflow */
+                if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
+                if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
+            }
+        /* over/underflow if x is not close to one */
+            if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
+            if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
+        /* now |1-x| is tiny <= 2**-20, suffice to compute 
+           log(x) by x-x^2/2+x^3/3-x^4/4 */
+            t = ax-one;         /* t has 20 trailing zeros */
+            w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+            u = ivln2_h*t;      /* ivln2_h has 21 sig. bits */
+            v = t*ivln2_l-w*ivln2;
+            t1 = u+v;
+            SET_LOW_WORD(t1,0);
+            t2 = v-(t1-u);
+        } else {
+            double ss,s2,s_h,s_l,t_h,t_l;
+            n = 0;
+        /* take care subnormal number */
+            if(ix<0x00100000)
+                {ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); }
+            n  += ((ix)>>20)-0x3ff;
+            j  = ix&0x000fffff;
+        /* determine interval */
+            ix = j|0x3ff00000;          /* normalize ix */
+            if(j<=0x3988E) k=0;         /* |x|<sqrt(3/2) */
+            else if(j<0xBB67A) k=1;     /* |x|<sqrt(3)   */
+            else {k=0;n+=1;ix -= 0x00100000;}
+            SET_HIGH_WORD(ax,ix);
+
+        /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+            u = ax-bp[k];               /* bp[0]=1.0, bp[1]=1.5 */
+            v = one/(ax+bp[k]);
+            ss = u*v;
+            s_h = ss;
+            SET_LOW_WORD(s_h,0);
+        /* t_h=ax+bp[k] High */
+            t_h = zero;
+            SET_HIGH_WORD(t_h,((ix>>1)|0x20000000)+0x00080000+(k<<18));
+            t_l = ax - (t_h-bp[k]);
+            s_l = v*((u-s_h*t_h)-s_h*t_l);
+        /* compute log(ax) */
+            s2 = ss*ss;
+            r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+            r += s_l*(s_h+ss);
+            s2  = s_h*s_h;
+            t_h = 3.0+s2+r;
+            SET_LOW_WORD(t_h,0);
+            t_l = r-((t_h-3.0)-s2);
+        /* u+v = ss*(1+...) */
+            u = s_h*t_h;
+            v = s_l*t_h+t_l*ss;
+        /* 2/(3log2)*(ss+...) */
+            p_h = u+v;
+            SET_LOW_WORD(p_h,0);
+            p_l = v-(p_h-u);
+            z_h = cp_h*p_h;             /* cp_h+cp_l = 2/(3*log2) */
+            z_l = cp_l*p_h+p_l*cp+dp_l[k];
+        /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+            t = (double)n;
+            t1 = (((z_h+z_l)+dp_h[k])+t);
+            SET_LOW_WORD(t1,0);
+            t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+        }
+
+    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+        y1  = y;
+        SET_LOW_WORD(y1,0);
+        p_l = (y-y1)*t1+y*t2;
+        p_h = y1*t1;
+        z = p_l+p_h;
+        EXTRACT_WORDS(j,i,z);
+        if (j>=0x40900000) {                            /* z >= 1024 */
+            if(((j-0x40900000)|i)!=0)                   /* if z > 1024 */
+                return s*huge*huge;                     /* overflow */
+            else {
+                if(p_l+ovt>z-p_h) return s*huge*huge;   /* overflow */
+            }
+        } else if((j&0x7fffffff)>=0x4090cc00 ) {        /* z <= -1075 */
+            if(((j-0xc090cc00)|i)!=0)           /* z < -1075 */
+                return s*tiny*tiny;             /* underflow */
+            else {
+                if(p_l<=z-p_h) return s*tiny*tiny;      /* underflow */
+            }
+        }
+    /*
+     * compute 2**(p_h+p_l)
+     */
+        i = j&0x7fffffff;
+        k = (i>>20)-0x3ff;
+        n = 0;
+        if(i>0x3fe00000) {              /* if |z| > 0.5, set n = [z+0.5] */
+            n = j+(0x00100000>>(k+1));
+            k = ((n&0x7fffffff)>>20)-0x3ff;     /* new k for n */
+            t = zero;
+            SET_HIGH_WORD(t,n&~(0x000fffff>>k));
+            n = ((n&0x000fffff)|0x00100000)>>(20-k);
+            if(j<0) n = -n;
+            p_h -= t;
+        } 
+        t = p_l+p_h;
+        SET_LOW_WORD(t,0);
+        u = t*lg2_h;
+        v = (p_l-(t-p_h))*lg2+t*lg2_l;
+        z = u+v;
+        w = v-(z-u);
+        t  = z*z;
+        t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+        r  = (z*t1)/(t1-two)-(w+z*w);
+        z  = one-(r-z);
+        GET_HIGH_WORD(j,z);
+        j += (n<<20);
+        if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */
+        else SET_HIGH_WORD(z,j);
+        return s*z;
+}
diff --git a/src/math/e_powf.c b/src/math/e_powf.c
new file mode 100644
index 00000000..ae61c246
--- /dev/null
+++ b/src/math/e_powf.c
@@ -0,0 +1,243 @@
+/* e_powf.c -- float version of e_pow.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 <math.h>
+#include "math_private.h"
+
+static const float
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */
+dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */
+zero    =  0.0,
+one     =  1.0,
+two     =  2.0,
+two24   =  16777216.0,  /* 0x4b800000 */
+huge    =  1.0e30,
+tiny    =  1.0e-30,
+        /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1  =  6.0000002384e-01, /* 0x3f19999a */
+L2  =  4.2857143283e-01, /* 0x3edb6db7 */
+L3  =  3.3333334327e-01, /* 0x3eaaaaab */
+L4  =  2.7272811532e-01, /* 0x3e8ba305 */
+L5  =  2.3066075146e-01, /* 0x3e6c3255 */
+L6  =  2.0697501302e-01, /* 0x3e53f142 */
+P1   =  1.6666667163e-01, /* 0x3e2aaaab */
+P2   = -2.7777778450e-03, /* 0xbb360b61 */
+P3   =  6.6137559770e-05, /* 0x388ab355 */
+P4   = -1.6533901999e-06, /* 0xb5ddea0e */
+P5   =  4.1381369442e-08, /* 0x3331bb4c */
+lg2  =  6.9314718246e-01, /* 0x3f317218 */
+lg2_h  =  6.93145752e-01, /* 0x3f317200 */
+lg2_l  =  1.42860654e-06, /* 0x35bfbe8c */
+ovt =  4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */
+cp    =  9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */
+cp_h  =  9.6179199219e-01, /* 0x3f763800 =head of cp */
+cp_l  =  4.7017383622e-06, /* 0x369dc3a0 =tail of cp_h */
+ivln2    =  1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */
+ivln2_h  =  1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/
+ivln2_l  =  7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/
+
+float
+powf(float x, float y)
+{
+        float z,ax,z_h,z_l,p_h,p_l;
+        float y1,t1,t2,r,s,sn,t,u,v,w;
+        int32_t i,j,k,yisint,n;
+        int32_t hx,hy,ix,iy,is;
+
+        GET_FLOAT_WORD(hx,x);
+        GET_FLOAT_WORD(hy,y);
+        ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
+
+    /* y==zero: x**0 = 1 */
+        if(iy==0) return one;
+
+    /* +-NaN return x+y */
+        if(ix > 0x7f800000 ||
+           iy > 0x7f800000)
+                return x+y;
+
+    /* determine if y is an odd int when x < 0
+     * yisint = 0       ... y is not an integer
+     * yisint = 1       ... y is an odd int
+     * yisint = 2       ... y is an even int
+     */
+        yisint  = 0;
+        if(hx<0) {
+            if(iy>=0x4b800000) yisint = 2; /* even integer y */
+            else if(iy>=0x3f800000) {
+                k = (iy>>23)-0x7f;         /* exponent */
+                j = iy>>(23-k);
+                if((j<<(23-k))==iy) yisint = 2-(j&1);
+            }
+        }
+
+    /* special value of y */
+        if (iy==0x7f800000) {   /* y is +-inf */
+            if (ix==0x3f800000)
+                return  y - y;  /* inf**+-1 is NaN */
+            else if (ix > 0x3f800000)/* (|x|>1)**+-inf = inf,0 */
+                return (hy>=0)? y: zero;
+            else                        /* (|x|<1)**-,+inf = inf,0 */
+                return (hy<0)?-y: zero;
+        }
+        if(iy==0x3f800000) {    /* y is  +-1 */
+            if(hy<0) return one/x; else return x;
+        }
+        if(hy==0x40000000) return x*x; /* y is  2 */
+        if(hy==0x3f000000) {    /* y is  0.5 */
+            if(hx>=0)   /* x >= +0 */
+            return sqrtf(x);
+        }
+
+        ax   = fabsf(x);
+    /* special value of x */
+        if(ix==0x7f800000||ix==0||ix==0x3f800000){
+            z = ax;                     /*x is +-0,+-inf,+-1*/
+            if(hy<0) z = one/z; /* z = (1/|x|) */
+            if(hx<0) {
+                if(((ix-0x3f800000)|yisint)==0) {
+                    z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+                } else if(yisint==1)
+                    z = -z;             /* (x<0)**odd = -(|x|**odd) */
+            }
+            return z;
+        }
+
+        n = ((uint32_t)hx>>31)-1;
+
+    /* (x<0)**(non-int) is NaN */
+        if((n|yisint)==0) return (x-x)/(x-x);
+
+        sn = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+        if((n|(yisint-1))==0) sn = -one;/* (-ve)**(odd int) */
+
+    /* |y| is huge */
+        if(iy>0x4d000000) { /* if |y| > 2**27 */
+        /* over/underflow if x is not close to one */
+            if(ix<0x3f7ffff8) return (hy<0)? sn*huge*huge:sn*tiny*tiny;
+            if(ix>0x3f800007) return (hy>0)? sn*huge*huge:sn*tiny*tiny;
+        /* now |1-x| is tiny <= 2**-20, suffice to compute
+           log(x) by x-x^2/2+x^3/3-x^4/4 */
+            t = ax-1;           /* t has 20 trailing zeros */
+            w = (t*t)*((float)0.5-t*((float)0.333333333333-t*(float)0.25));
+            u = ivln2_h*t;      /* ivln2_h has 16 sig. bits */
+            v = t*ivln2_l-w*ivln2;
+            t1 = u+v;
+            GET_FLOAT_WORD(is,t1);
+            SET_FLOAT_WORD(t1,is&0xfffff000);
+            t2 = v-(t1-u);
+        } else {
+            float s2,s_h,s_l,t_h,t_l;
+            n = 0;
+        /* take care subnormal number */
+            if(ix<0x00800000)
+                {ax *= two24; n -= 24; GET_FLOAT_WORD(ix,ax); }
+            n  += ((ix)>>23)-0x7f;
+            j  = ix&0x007fffff;
+        /* determine interval */
+            ix = j|0x3f800000;          /* normalize ix */
+            if(j<=0x1cc471) k=0;        /* |x|<sqrt(3/2) */
+            else if(j<0x5db3d7) k=1;    /* |x|<sqrt(3)   */
+            else {k=0;n+=1;ix -= 0x00800000;}
+            SET_FLOAT_WORD(ax,ix);
+
+        /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+            u = ax-bp[k];               /* bp[0]=1.0, bp[1]=1.5 */
+            v = one/(ax+bp[k]);
+            s = u*v;
+            s_h = s;
+            GET_FLOAT_WORD(is,s_h);
+            SET_FLOAT_WORD(s_h,is&0xfffff000);
+        /* t_h=ax+bp[k] High */
+            is = ((ix>>1)&0xfffff000)|0x20000000;
+            SET_FLOAT_WORD(t_h,is+0x00400000+(k<<21));
+            t_l = ax - (t_h-bp[k]);
+            s_l = v*((u-s_h*t_h)-s_h*t_l);
+        /* compute log(ax) */
+            s2 = s*s;
+            r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+            r += s_l*(s_h+s);
+            s2  = s_h*s_h;
+            t_h = (float)3.0+s2+r;
+            GET_FLOAT_WORD(is,t_h);
+            SET_FLOAT_WORD(t_h,is&0xfffff000);
+            t_l = r-((t_h-(float)3.0)-s2);
+        /* u+v = s*(1+...) */
+            u = s_h*t_h;
+            v = s_l*t_h+t_l*s;
+        /* 2/(3log2)*(s+...) */
+            p_h = u+v;
+            GET_FLOAT_WORD(is,p_h);
+            SET_FLOAT_WORD(p_h,is&0xfffff000);
+            p_l = v-(p_h-u);
+            z_h = cp_h*p_h;             /* cp_h+cp_l = 2/(3*log2) */
+            z_l = cp_l*p_h+p_l*cp+dp_l[k];
+        /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+            t = (float)n;
+            t1 = (((z_h+z_l)+dp_h[k])+t);
+            GET_FLOAT_WORD(is,t1);
+            SET_FLOAT_WORD(t1,is&0xfffff000);
+            t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+        }
+
+    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+        GET_FLOAT_WORD(is,y);
+        SET_FLOAT_WORD(y1,is&0xfffff000);
+        p_l = (y-y1)*t1+y*t2;
+        p_h = y1*t1;
+        z = p_l+p_h;
+        GET_FLOAT_WORD(j,z);
+        if (j>0x43000000)                               /* if z > 128 */
+            return sn*huge*huge;                        /* overflow */
+        else if (j==0x43000000) {                       /* if z == 128 */
+            if(p_l+ovt>z-p_h) return sn*huge*huge;      /* overflow */
+        }
+        else if ((j&0x7fffffff)>0x43160000)             /* z <= -150 */
+            return sn*tiny*tiny;                        /* underflow */
+        else if (j==0xc3160000){                        /* z == -150 */
+            if(p_l<=z-p_h) return sn*tiny*tiny;         /* underflow */
+        }
+    /*
+     * compute 2**(p_h+p_l)
+     */
+        i = j&0x7fffffff;
+        k = (i>>23)-0x7f;
+        n = 0;
+        if(i>0x3f000000) {              /* if |z| > 0.5, set n = [z+0.5] */
+            n = j+(0x00800000>>(k+1));
+            k = ((n&0x7fffffff)>>23)-0x7f;      /* new k for n */
+            SET_FLOAT_WORD(t,n&~(0x007fffff>>k));
+            n = ((n&0x007fffff)|0x00800000)>>(23-k);
+            if(j<0) n = -n;
+            p_h -= t;
+        }
+        t = p_l+p_h;
+        GET_FLOAT_WORD(is,t);
+        SET_FLOAT_WORD(t,is&0xffff8000);
+        u = t*lg2_h;
+        v = (p_l-(t-p_h))*lg2+t*lg2_l;
+        z = u+v;
+        w = v-(z-u);
+        t  = z*z;
+        t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+        r  = (z*t1)/(t1-two)-(w+z*w);
+        z  = one-(r-z);
+        GET_FLOAT_WORD(j,z);
+        j += (n<<23);
+        if((j>>23)<=0) z = scalbnf(z,n);        /* subnormal output */
+        else SET_FLOAT_WORD(z,j);
+        return sn*z;
+}
diff --git a/src/math/e_rem_pio2.c b/src/math/e_rem_pio2.c
new file mode 100644
index 00000000..9eee36ae
--- /dev/null
+++ b/src/math/e_rem_pio2.c
@@ -0,0 +1,163 @@
+
+/* @(#)e_rem_pio2.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_rem_pio2(x,y)
+ * 
+ * return the remainder of x rem pi/2 in y[0]+y[1] 
+ * use __kernel_rem_pio2()
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi 
+ */
+static const int32_t two_over_pi[] = {
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, 
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, 
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, 
+};
+
+static const int32_t npio2_hw[] = {
+0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C,
+0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C,
+0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A,
+0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C,
+0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB,
+0x404858EB, 0x404921FB,
+};
+
+/*
+ * invpio2:  53 bits of 2/pi
+ * pio2_1:   first  33 bit of pi/2
+ * pio2_1t:  pi/2 - pio2_1
+ * pio2_2:   second 33 bit of pi/2
+ * pio2_2t:  pi/2 - (pio2_1+pio2_2)
+ * pio2_3:   third  33 bit of pi/2
+ * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const double
+zero =  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+two24 =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+invpio2 =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1  =  1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
+pio2_1t =  6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
+pio2_2  =  6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
+pio2_2t =  2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
+pio2_3  =  2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
+pio2_3t =  8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
+
+int32_t __ieee754_rem_pio2(double x, double *y)
+{
+        double z,w,t,r,fn;
+        double tx[3];
+        int32_t e0,i,j,nx,n,ix,hx;
+        uint32_t low;
+
+        GET_HIGH_WORD(hx,x);            /* high word of x */
+        ix = hx&0x7fffffff;
+        if(ix<=0x3fe921fb)   /* |x| ~<= pi/4 , no need for reduction */
+            {y[0] = x; y[1] = 0; return 0;}
+        if(ix<0x4002d97c) {  /* |x| < 3pi/4, special case with n=+-1 */
+            if(hx>0) { 
+                z = x - pio2_1;
+                if(ix!=0x3ff921fb) {    /* 33+53 bit pi is good enough */
+                    y[0] = z - pio2_1t;
+                    y[1] = (z-y[0])-pio2_1t;
+                } else {                /* near pi/2, use 33+33+53 bit pi */
+                    z -= pio2_2;
+                    y[0] = z - pio2_2t;
+                    y[1] = (z-y[0])-pio2_2t;
+                }
+                return 1;
+            } else {    /* negative x */
+                z = x + pio2_1;
+                if(ix!=0x3ff921fb) {    /* 33+53 bit pi is good enough */
+                    y[0] = z + pio2_1t;
+                    y[1] = (z-y[0])+pio2_1t;
+                } else {                /* near pi/2, use 33+33+53 bit pi */
+                    z += pio2_2;
+                    y[0] = z + pio2_2t;
+                    y[1] = (z-y[0])+pio2_2t;
+                }
+                return -1;
+            }
+        }
+        if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */
+            t  = fabs(x);
+            n  = (int32_t) (t*invpio2+half);
+            fn = (double)n;
+            r  = t-fn*pio2_1;
+            w  = fn*pio2_1t;    /* 1st round good to 85 bit */
+            if(n<32&&ix!=npio2_hw[n-1]) {       
+                y[0] = r-w;     /* quick check no cancellation */
+            } else {
+                uint32_t high;
+                j  = ix>>20;
+                y[0] = r-w; 
+                GET_HIGH_WORD(high,y[0]);
+                i = j-((high>>20)&0x7ff);
+                if(i>16) {  /* 2nd iteration needed, good to 118 */
+                    t  = r;
+                    w  = fn*pio2_2;     
+                    r  = t-w;
+                    w  = fn*pio2_2t-((t-r)-w);  
+                    y[0] = r-w;
+                    GET_HIGH_WORD(high,y[0]);
+                    i = j-((high>>20)&0x7ff);
+                    if(i>49)  { /* 3rd iteration need, 151 bits acc */
+                        t  = r; /* will cover all possible cases */
+                        w  = fn*pio2_3; 
+                        r  = t-w;
+                        w  = fn*pio2_3t-((t-r)-w);      
+                        y[0] = r-w;
+                    }
+                }
+            }
+            y[1] = (r-y[0])-w;
+            if(hx<0)    {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+            else         return n;
+        }
+    /* 
+     * all other (large) arguments
+     */
+        if(ix>=0x7ff00000) {            /* x is inf or NaN */
+            y[0]=y[1]=x-x; return 0;
+        }
+    /* set z = scalbn(|x|,ilogb(x)-23) */
+        GET_LOW_WORD(low,x);
+        e0      = (ix>>20)-1046;        /* e0 = ilogb(z)-23; */
+	INSERT_WORDS(z, ix - ((int32_t)(e0<<20)), low);
+        for(i=0;i<2;i++) {
+                tx[i] = (double)((int32_t)(z));
+                z     = (z-tx[i])*two24;
+        }
+        tx[2] = z;
+        nx = 3;
+        while(tx[nx-1]==zero) nx--;     /* skip zero term */
+        n  =  __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi);
+        if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+        return n;
+}
diff --git a/src/math/e_rem_pio2f.c b/src/math/e_rem_pio2f.c
new file mode 100644
index 00000000..4992ea0c
--- /dev/null
+++ b/src/math/e_rem_pio2f.c
@@ -0,0 +1,175 @@
+/* e_rem_pio2f.c -- float version of e_rem_pio2.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.
+ * ====================================================
+ */
+
+/* __ieee754_rem_pio2f(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use __kernel_rem_pio2f()
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ */
+static const int32_t two_over_pi[] = {
+0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC,
+0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62,
+0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63,
+0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A,
+0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09,
+0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29,
+0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44,
+0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41,
+0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C,
+0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8,
+0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11,
+0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF,
+0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E,
+0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5,
+0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92,
+0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08,
+0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0,
+0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3,
+0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85,
+0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80,
+0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA,
+0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B,
+};
+
+/* This array is like the one in e_rem_pio2.c, but the numbers are
+   single precision and the last 8 bits are forced to 0.  */
+static const int32_t npio2_hw[] = {
+0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00,
+0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00,
+0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100,
+0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00,
+0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00,
+0x4242c700, 0x42490f00
+};
+
+/*
+ * invpio2:  24 bits of 2/pi
+ * pio2_1:   first  17 bit of pi/2
+ * pio2_1t:  pi/2 - pio2_1
+ * pio2_2:   second 17 bit of pi/2
+ * pio2_2t:  pi/2 - (pio2_1+pio2_2)
+ * pio2_3:   third  17 bit of pi/2
+ * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const float
+zero =  0.0000000000e+00, /* 0x00000000 */
+half =  5.0000000000e-01, /* 0x3f000000 */
+two8 =  2.5600000000e+02, /* 0x43800000 */
+invpio2 =  6.3661980629e-01, /* 0x3f22f984 */
+pio2_1  =  1.5707855225e+00, /* 0x3fc90f80 */
+pio2_1t =  1.0804334124e-05, /* 0x37354443 */
+pio2_2  =  1.0804273188e-05, /* 0x37354400 */
+pio2_2t =  6.0770999344e-11, /* 0x2e85a308 */
+pio2_3  =  6.0770943833e-11, /* 0x2e85a300 */
+pio2_3t =  6.1232342629e-17; /* 0x248d3132 */
+
+int32_t __ieee754_rem_pio2f(float x, float *y)
+{
+        float z,w,t,r,fn;
+        float tx[3];
+        int32_t e0,i,j,nx,n,ix,hx;
+
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix<=0x3f490fd8)   /* |x| ~<= pi/4 , no need for reduction */
+            {y[0] = x; y[1] = 0; return 0;}
+        if(ix<0x4016cbe4) {  /* |x| < 3pi/4, special case with n=+-1 */
+            if(hx>0) {
+                z = x - pio2_1;
+                if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
+                    y[0] = z - pio2_1t;
+                    y[1] = (z-y[0])-pio2_1t;
+                } else {                /* near pi/2, use 24+24+24 bit pi */
+                    z -= pio2_2;
+                    y[0] = z - pio2_2t;
+                    y[1] = (z-y[0])-pio2_2t;
+                }
+                return 1;
+            } else {    /* negative x */
+                z = x + pio2_1;
+                if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
+                    y[0] = z + pio2_1t;
+                    y[1] = (z-y[0])+pio2_1t;
+                } else {                /* near pi/2, use 24+24+24 bit pi */
+                    z += pio2_2;
+                    y[0] = z + pio2_2t;
+                    y[1] = (z-y[0])+pio2_2t;
+                }
+                return -1;
+            }
+        }
+        if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */
+            t  = fabsf(x);
+            n  = (int32_t) (t*invpio2+half);
+            fn = (float)n;
+            r  = t-fn*pio2_1;
+            w  = fn*pio2_1t;    /* 1st round good to 40 bit */
+            if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) {
+                y[0] = r-w;     /* quick check no cancellation */
+            } else {
+                uint32_t high;
+                j  = ix>>23;
+                y[0] = r-w;
+                GET_FLOAT_WORD(high,y[0]);
+                i = j-((high>>23)&0xff);
+                if(i>8) {  /* 2nd iteration needed, good to 57 */
+                    t  = r;
+                    w  = fn*pio2_2;
+                    r  = t-w;
+                    w  = fn*pio2_2t-((t-r)-w);
+                    y[0] = r-w;
+                    GET_FLOAT_WORD(high,y[0]);
+                    i = j-((high>>23)&0xff);
+                    if(i>25)  { /* 3rd iteration need, 74 bits acc */
+                        t  = r; /* will cover all possible cases */
+                        w  = fn*pio2_3;
+                        r  = t-w;
+                        w  = fn*pio2_3t-((t-r)-w);
+                        y[0] = r-w;
+                    }
+                }
+            }
+            y[1] = (r-y[0])-w;
+            if(hx<0)    {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+            else         return n;
+        }
+    /*
+     * all other (large) arguments
+     */
+        if(ix>=0x7f800000) {            /* x is inf or NaN */
+            y[0]=y[1]=x-x; return 0;
+        }
+    /* set z = scalbn(|x|,ilogb(x)-7) */
+        e0      = (ix>>23)-134;         /* e0 = ilogb(z)-7; */
+        SET_FLOAT_WORD(z, ix - ((int32_t)(e0<<23)));
+        for(i=0;i<2;i++) {
+                tx[i] = (float)((int32_t)(z));
+                z     = (z-tx[i])*two8;
+        }
+        tx[2] = z;
+        nx = 3;
+        while(tx[nx-1]==zero) nx--;     /* skip zero term */
+        n  =  __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi);
+        if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+        return n;
+}
diff --git a/src/math/e_remainder.c b/src/math/e_remainder.c
new file mode 100644
index 00000000..9cb56919
--- /dev/null
+++ b/src/math/e_remainder.c
@@ -0,0 +1,69 @@
+
+/* @(#)e_remainder.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* remainder(x,p)
+ * Return :                  
+ *      returns  x REM p  =  x - [x/p]*p as if in infinite 
+ *      precise arithmetic, where [x/p] is the (infinite bit) 
+ *      integer nearest x/p (in half way case choose the even one).
+ * Method : 
+ *      Based on fmod() return x-[x/p]chopped*p exactlp.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double zero = 0.0;
+
+
+double
+remainder(double x, double p)
+{
+        int32_t hx,hp;
+        uint32_t sx,lx,lp;
+        double p_half;
+
+        EXTRACT_WORDS(hx,lx,x);
+        EXTRACT_WORDS(hp,lp,p);
+        sx = hx&0x80000000;
+        hp &= 0x7fffffff;
+        hx &= 0x7fffffff;
+
+    /* purge off exception values */
+        if((hp|lp)==0) return (x*p)/(x*p);      /* p = 0 */
+        if((hx>=0x7ff00000)||                   /* x not finite */
+          ((hp>=0x7ff00000)&&                   /* p is NaN */
+          (((hp-0x7ff00000)|lp)!=0)))
+            return (x*p)/(x*p);
+
+
+        if (hp<=0x7fdfffff) x = fmod(x,p+p);  /* now x < 2p */
+        if (((hx-hp)|(lx-lp))==0) return zero*x;
+        x  = fabs(x);
+        p  = fabs(p);
+        if (hp<0x00200000) {
+            if(x+x>p) {
+                x-=p;
+                if(x+x>=p) x -= p;
+            }
+        } else {
+            p_half = 0.5*p;
+            if(x>p_half) {
+                x-=p;
+                if(x>=p_half) x -= p;
+            }
+        }
+        GET_HIGH_WORD(hx,x);
+        SET_HIGH_WORD(x,hx^sx);
+        return x;
+}
diff --git a/src/math/e_remainderf.c b/src/math/e_remainderf.c
new file mode 100644
index 00000000..c292367d
--- /dev/null
+++ b/src/math/e_remainderf.c
@@ -0,0 +1,61 @@
+/* e_remainderf.c -- float version of e_remainder.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 <math.h>
+#include "math_private.h"
+
+static const float zero = 0.0;
+
+
+float
+remainderf(float x, float p)
+{
+        int32_t hx,hp;
+        uint32_t sx;
+        float p_half;
+
+        GET_FLOAT_WORD(hx,x);
+        GET_FLOAT_WORD(hp,p);
+        sx = hx&0x80000000;
+        hp &= 0x7fffffff;
+        hx &= 0x7fffffff;
+
+    /* purge off exception values */
+        if(hp==0) return (x*p)/(x*p);           /* p = 0 */
+        if((hx>=0x7f800000)||                   /* x not finite */
+          ((hp>0x7f800000)))                    /* p is NaN */
+            return (x*p)/(x*p);
+
+
+        if (hp<=0x7effffff) x = fmodf(x,p+p); /* now x < 2p */
+        if ((hx-hp)==0) return zero*x;
+        x  = fabsf(x);
+        p  = fabsf(p);
+        if (hp<0x01000000) {
+            if(x+x>p) {
+                x-=p;
+                if(x+x>=p) x -= p;
+            }
+        } else {
+            p_half = (float)0.5*p;
+            if(x>p_half) {
+                x-=p;
+                if(x>=p_half) x -= p;
+            }
+        }
+        GET_FLOAT_WORD(hx,x);
+        SET_FLOAT_WORD(x,hx^sx);
+        return x;
+}
diff --git a/src/math/e_scalb.c b/src/math/e_scalb.c
new file mode 100644
index 00000000..cee2b44f
--- /dev/null
+++ b/src/math/e_scalb.c
@@ -0,0 +1,35 @@
+
+/* @(#)e_scalb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * scalb(x, fn) is provide for
+ * passing various standard test suite. One 
+ * should use scalbn() instead.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+scalb(double x, double fn)
+{
+        if (isnan(x)||isnan(fn)) return x*fn;
+        if (!isfinite(fn)) {
+            if(fn>0.0) return x*fn;
+            else       return x/(-fn);
+        }
+        if (rint(fn)!=fn) return (fn-fn)/(fn-fn);
+        if ( fn > 65000.0) return scalbn(x, 65000);
+        if (-fn > 65000.0) return scalbn(x,-65000);
+        return scalbn(x,(int)fn);
+}
diff --git a/src/math/e_scalbf.c b/src/math/e_scalbf.c
new file mode 100644
index 00000000..de7d7f67
--- /dev/null
+++ b/src/math/e_scalbf.c
@@ -0,0 +1,31 @@
+/* e_scalbf.c -- float version of e_scalb.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 <math.h>
+#include "math_private.h"
+
+float
+scalbf(float x, float fn)
+{
+        if (isnan(x)||isnan(fn)) return x*fn;
+        if (!isfinite(fn)) {
+            if(fn>(float)0.0) return x*fn;
+            else       return x/(-fn);
+        }
+        if (rintf(fn)!=fn) return (fn-fn)/(fn-fn);
+        if ( fn > (float)65000.0) return scalbnf(x, 65000);
+        if (-fn > (float)65000.0) return scalbnf(x,-65000);
+        return scalbnf(x,(int)fn);
+}
diff --git a/src/math/e_sinh.c b/src/math/e_sinh.c
new file mode 100644
index 00000000..3a574274
--- /dev/null
+++ b/src/math/e_sinh.c
@@ -0,0 +1,75 @@
+
+/* @(#)e_sinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* sinh(x)
+ * Method : 
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ *      1. Replace x by |x| (sinh(-x) = -sinh(x)). 
+ *      2. 
+ *                                                  E + E/(E+1)
+ *          0        <= x <= 22     :  sinh(x) := --------------, E=expm1(x)
+ *                                                      2
+ *
+ *          22       <= x <= lnovft :  sinh(x) := exp(x)/2 
+ *          lnovft   <= x <= ln2ovft:  sinh(x) := exp(x/2)/2 * exp(x/2)
+ *          ln2ovft  <  x           :  sinh(x) := x*shuge (overflow)
+ *
+ * Special cases:
+ *      sinh(x) is |x| if x is +INF, -INF, or NaN.
+ *      only sinh(0)=0 is exact for finite x.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one = 1.0, shuge = 1.0e307;
+
+double
+sinh(double x)
+{
+        double t,w,h;
+        int32_t ix,jx;
+        uint32_t lx;
+
+    /* High word of |x|. */
+        GET_HIGH_WORD(jx,x);
+        ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7ff00000) return x+x;  
+
+        h = 0.5;
+        if (jx<0) h = -h;
+    /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+        if (ix < 0x40360000) {          /* |x|<22 */
+            if (ix<0x3e300000)          /* |x|<2**-28 */
+                if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+            t = expm1(fabs(x));
+            if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one));
+            return h*(t+t/(t+one));
+        }
+
+    /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+        if (ix < 0x40862E42)  return h*exp(fabs(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+        GET_LOW_WORD(lx,x);
+        if (ix<0x408633CE || ((ix==0x408633ce)&&(lx<=(uint32_t)0x8fb9f87d))) {
+            w = exp(0.5*fabs(x));
+            t = h*w;
+            return t*w;
+        }
+
+    /* |x| > overflowthresold, sinh(x) overflow */
+        return x*shuge;
+}
diff --git a/src/math/e_sinhf.c b/src/math/e_sinhf.c
new file mode 100644
index 00000000..fe60608a
--- /dev/null
+++ b/src/math/e_sinhf.c
@@ -0,0 +1,56 @@
+/* e_sinhf.c -- float version of e_sinh.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 <math.h>
+#include "math_private.h"
+
+static const float one = 1.0, shuge = 1.0e37;
+
+float
+sinhf(float x)
+{
+        float t,w,h;
+        int32_t ix,jx;
+
+        GET_FLOAT_WORD(jx,x);
+        ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7f800000) return x+x;
+
+        h = 0.5;
+        if (jx<0) h = -h;
+    /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+        if (ix < 0x41b00000) {          /* |x|<22 */
+            if (ix<0x31800000)          /* |x|<2**-28 */
+                if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+            t = expm1f(fabsf(x));
+            if(ix<0x3f800000) return h*((float)2.0*t-t*t/(t+one));
+            return h*(t+t/(t+one));
+        }
+
+    /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+        if (ix < 0x42b17180)  return h*expf(fabsf(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+        if (ix<=0x42b2d4fc) {
+            w = expf((float)0.5*fabsf(x));
+            t = h*w;
+            return t*w;
+        }
+
+    /* |x| > overflowthresold, sinh(x) overflow */
+        return x*shuge;
+}
diff --git a/src/math/e_sqrt.c b/src/math/e_sqrt.c
new file mode 100644
index 00000000..2bc68747
--- /dev/null
+++ b/src/math/e_sqrt.c
@@ -0,0 +1,442 @@
+
+/* @(#)e_sqrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* sqrt(x)
+ * Return correctly rounded sqrt.
+ *           ------------------------------------------
+ *           |  Use the hardware sqrt if you have one |
+ *           ------------------------------------------
+ * Method: 
+ *   Bit by bit method using integer arithmetic. (Slow, but portable) 
+ *   1. Normalization
+ *      Scale x to y in [1,4) with even powers of 2: 
+ *      find an integer k such that  1 <= (y=x*2^(2k)) < 4, then
+ *              sqrt(x) = 2^k * sqrt(y)
+ *   2. Bit by bit computation
+ *      Let q  = sqrt(y) truncated to i bit after binary point (q = 1),
+ *           i                                                   0
+ *                                     i+1         2
+ *          s  = 2*q , and      y  =  2   * ( y - q  ).         (1)
+ *           i      i            i                 i
+ *                                                        
+ *      To compute q    from q , one checks whether 
+ *                  i+1       i                       
+ *
+ *                            -(i+1) 2
+ *                      (q + 2      ) <= y.                     (2)
+ *                        i
+ *                                                            -(i+1)
+ *      If (2) is false, then q   = q ; otherwise q   = q  + 2      .
+ *                             i+1   i             i+1   i
+ *
+ *      With some algebric manipulation, it is not difficult to see
+ *      that (2) is equivalent to 
+ *                             -(i+1)
+ *                      s  +  2       <= y                      (3)
+ *                       i                i
+ *
+ *      The advantage of (3) is that s  and y  can be computed by 
+ *                                    i      i
+ *      the following recurrence formula:
+ *          if (3) is false
+ *
+ *          s     =  s  ,       y    = y   ;                    (4)
+ *           i+1      i          i+1    i
+ *
+ *          otherwise,
+ *                         -i                     -(i+1)
+ *          s     =  s  + 2  ,  y    = y  -  s  - 2             (5)
+ *           i+1      i          i+1    i     i
+ *                              
+ *      One may easily use induction to prove (4) and (5). 
+ *      Note. Since the left hand side of (3) contain only i+2 bits,
+ *            it does not necessary to do a full (53-bit) comparison 
+ *            in (3).
+ *   3. Final rounding
+ *      After generating the 53 bits result, we compute one more bit.
+ *      Together with the remainder, we can decide whether the
+ *      result is exact, bigger than 1/2ulp, or less than 1/2ulp
+ *      (it will never equal to 1/2ulp).
+ *      The rounding mode can be detected by checking whether
+ *      huge + tiny is equal to huge, and whether huge - tiny is
+ *      equal to huge for some floating point number "huge" and "tiny".
+ *              
+ * Special cases:
+ *      sqrt(+-0) = +-0         ... exact
+ *      sqrt(inf) = inf
+ *      sqrt(-ve) = NaN         ... with invalid signal
+ *      sqrt(NaN) = NaN         ... with invalid signal for signaling NaN
+ *
+ * Other methods : see the appended file at the end of the program below.
+ *---------------
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static  const double    one     = 1.0, tiny=1.0e-300;
+
+double
+sqrt(double x)
+{
+        double z;
+        int32_t sign = (int)0x80000000;
+        int32_t ix0,s0,q,m,t,i;
+        uint32_t r,t1,s1,ix1,q1;
+
+        EXTRACT_WORDS(ix0,ix1,x);
+
+    /* take care of Inf and NaN */
+        if((ix0&0x7ff00000)==0x7ff00000) {                      
+            return x*x+x;               /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+                                           sqrt(-inf)=sNaN */
+        } 
+    /* take care of zero */
+        if(ix0<=0) {
+            if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
+            else if(ix0<0)
+                return (x-x)/(x-x);             /* sqrt(-ve) = sNaN */
+        }
+    /* normalize x */
+        m = (ix0>>20);
+        if(m==0) {                              /* subnormal x */
+            while(ix0==0) {
+                m -= 21;
+                ix0 |= (ix1>>11); ix1 <<= 21;
+            }
+            for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
+            m -= i-1;
+            ix0 |= (ix1>>(32-i));
+            ix1 <<= i;
+        }
+        m -= 1023;      /* unbias exponent */
+        ix0 = (ix0&0x000fffff)|0x00100000;
+        if(m&1){        /* odd m, double x to make it even */
+            ix0 += ix0 + ((ix1&sign)>>31);
+            ix1 += ix1;
+        }
+        m >>= 1;        /* m = [m/2] */
+
+    /* generate sqrt(x) bit by bit */
+        ix0 += ix0 + ((ix1&sign)>>31);
+        ix1 += ix1;
+        q = q1 = s0 = s1 = 0;   /* [q,q1] = sqrt(x) */
+        r = 0x00200000;         /* r = moving bit from right to left */
+
+        while(r!=0) {
+            t = s0+r; 
+            if(t<=ix0) { 
+                s0   = t+r; 
+                ix0 -= t; 
+                q   += r; 
+            } 
+            ix0 += ix0 + ((ix1&sign)>>31);
+            ix1 += ix1;
+            r>>=1;
+        }
+
+        r = sign;
+        while(r!=0) {
+            t1 = s1+r; 
+            t  = s0;
+            if((t<ix0)||((t==ix0)&&(t1<=ix1))) { 
+                s1  = t1+r;
+                if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
+                ix0 -= t;
+                if (ix1 < t1) ix0 -= 1;
+                ix1 -= t1;
+                q1  += r;
+            }
+            ix0 += ix0 + ((ix1&sign)>>31);
+            ix1 += ix1;
+            r>>=1;
+        }
+
+    /* use floating add to find out rounding direction */
+        if((ix0|ix1)!=0) {
+            z = one-tiny; /* trigger inexact flag */
+            if (z>=one) {
+                z = one+tiny;
+                if (q1==(uint32_t)0xffffffff) { q1=0; q += 1;}
+                else if (z>one) {
+                    if (q1==(uint32_t)0xfffffffe) q+=1;
+                    q1+=2; 
+                } else
+                    q1 += (q1&1);
+            }
+        }
+        ix0 = (q>>1)+0x3fe00000;
+        ix1 =  q1>>1;
+        if ((q&1)==1) ix1 |= sign;
+        ix0 += (m <<20);
+        INSERT_WORDS(z,ix0,ix1);
+        return z;
+}
+
+/*
+Other methods  (use floating-point arithmetic)
+-------------
+(This is a copy of a drafted paper by Prof W. Kahan 
+and K.C. Ng, written in May, 1986)
+
+        Two algorithms are given here to implement sqrt(x) 
+        (IEEE double precision arithmetic) in software.
+        Both supply sqrt(x) correctly rounded. The first algorithm (in
+        Section A) uses newton iterations and involves four divisions.
+        The second one uses reciproot iterations to avoid division, but
+        requires more multiplications. Both algorithms need the ability
+        to chop results of arithmetic operations instead of round them, 
+        and the INEXACT flag to indicate when an arithmetic operation
+        is executed exactly with no roundoff error, all part of the 
+        standard (IEEE 754-1985). The ability to perform shift, add,
+        subtract and logical AND operations upon 32-bit words is needed
+        too, though not part of the standard.
+
+A.  sqrt(x) by Newton Iteration
+
+   (1)  Initial approximation
+
+        Let x0 and x1 be the leading and the trailing 32-bit words of
+        a floating point number x (in IEEE double format) respectively 
+
+            1    11                  52                           ...widths
+           ------------------------------------------------------
+        x: |s|    e     |             f                         |
+           ------------------------------------------------------
+              msb    lsb  msb                                 lsb ...order
+
+ 
+             ------------------------        ------------------------
+        x0:  |s|   e    |    f1     |    x1: |          f2           |
+             ------------------------        ------------------------
+
+        By performing shifts and subtracts on x0 and x1 (both regarded
+        as integers), we obtain an 8-bit approximation of sqrt(x) as
+        follows.
+
+                k  := (x0>>1) + 0x1ff80000;
+                y0 := k - T1[31&(k>>15)].       ... y ~ sqrt(x) to 8 bits
+        Here k is a 32-bit integer and T1[] is an integer array containing
+        correction terms. Now magically the floating value of y (y's
+        leading 32-bit word is y0, the value of its trailing word is 0)
+        approximates sqrt(x) to almost 8-bit.
+
+        Value of T1:
+        static int T1[32]= {
+        0,      1024,   3062,   5746,   9193,   13348,  18162,  23592,
+        29598,  36145,  43202,  50740,  58733,  67158,  75992,  85215,
+        83599,  71378,  60428,  50647,  41945,  34246,  27478,  21581,
+        16499,  12183,  8588,   5674,   3403,   1742,   661,    130,};
+
+    (2) Iterative refinement
+
+        Apply Heron's rule three times to y, we have y approximates 
+        sqrt(x) to within 1 ulp (Unit in the Last Place):
+
+                y := (y+x/y)/2          ... almost 17 sig. bits
+                y := (y+x/y)/2          ... almost 35 sig. bits
+                y := y-(y-x/y)/2        ... within 1 ulp
+
+
+        Remark 1.
+            Another way to improve y to within 1 ulp is:
+
+                y := (y+x/y)            ... almost 17 sig. bits to 2*sqrt(x)
+                y := y - 0x00100006     ... almost 18 sig. bits to sqrt(x)
+
+                                2
+                            (x-y )*y
+                y := y + 2* ----------  ...within 1 ulp
+                               2
+                             3y  + x
+
+
+        This formula has one division fewer than the one above; however,
+        it requires more multiplications and additions. Also x must be
+        scaled in advance to avoid spurious overflow in evaluating the
+        expression 3y*y+x. Hence it is not recommended uless division
+        is slow. If division is very slow, then one should use the 
+        reciproot algorithm given in section B.
+
+    (3) Final adjustment
+
+        By twiddling y's last bit it is possible to force y to be 
+        correctly rounded according to the prevailing rounding mode
+        as follows. Let r and i be copies of the rounding mode and
+        inexact flag before entering the square root program. Also we
+        use the expression y+-ulp for the next representable floating
+        numbers (up and down) of y. Note that y+-ulp = either fixed
+        point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+        mode.
+
+                I := FALSE;     ... reset INEXACT flag I
+                R := RZ;        ... set rounding mode to round-toward-zero
+                z := x/y;       ... chopped quotient, possibly inexact
+                If(not I) then {        ... if the quotient is exact
+                    if(z=y) {
+                        I := i;  ... restore inexact flag
+                        R := r;  ... restore rounded mode
+                        return sqrt(x):=y.
+                    } else {
+                        z := z - ulp;   ... special rounding
+                    }
+                }
+                i := TRUE;              ... sqrt(x) is inexact
+                If (r=RN) then z=z+ulp  ... rounded-to-nearest
+                If (r=RP) then {        ... round-toward-+inf
+                    y = y+ulp; z=z+ulp;
+                }
+                y := y+z;               ... chopped sum
+                y0:=y0-0x00100000;      ... y := y/2 is correctly rounded.
+                I := i;                 ... restore inexact flag
+                R := r;                 ... restore rounded mode
+                return sqrt(x):=y.
+                    
+    (4) Special cases
+
+        Square root of +inf, +-0, or NaN is itself;
+        Square root of a negative number is NaN with invalid signal.
+
+
+B.  sqrt(x) by Reciproot Iteration
+
+   (1)  Initial approximation
+
+        Let x0 and x1 be the leading and the trailing 32-bit words of
+        a floating point number x (in IEEE double format) respectively
+        (see section A). By performing shifs and subtracts on x0 and y0,
+        we obtain a 7.8-bit approximation of 1/sqrt(x) as follows.
+
+            k := 0x5fe80000 - (x0>>1);
+            y0:= k - T2[63&(k>>14)].    ... y ~ 1/sqrt(x) to 7.8 bits
+
+        Here k is a 32-bit integer and T2[] is an integer array 
+        containing correction terms. Now magically the floating
+        value of y (y's leading 32-bit word is y0, the value of
+        its trailing word y1 is set to zero) approximates 1/sqrt(x)
+        to almost 7.8-bit.
+
+        Value of T2:
+        static int T2[64]= {
+        0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866,
+        0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f,
+        0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d,
+        0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0,
+        0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989,
+        0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd,
+        0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e,
+        0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,};
+
+    (2) Iterative refinement
+
+        Apply Reciproot iteration three times to y and multiply the
+        result by x to get an approximation z that matches sqrt(x)
+        to about 1 ulp. To be exact, we will have 
+                -1ulp < sqrt(x)-z<1.0625ulp.
+        
+        ... set rounding mode to Round-to-nearest
+           y := y*(1.5-0.5*x*y*y)       ... almost 15 sig. bits to 1/sqrt(x)
+           y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x)
+        ... special arrangement for better accuracy
+           z := x*y                     ... 29 bits to sqrt(x), with z*y<1
+           z := z + 0.5*z*(1-z*y)       ... about 1 ulp to sqrt(x)
+
+        Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that
+        (a) the term z*y in the final iteration is always less than 1; 
+        (b) the error in the final result is biased upward so that
+                -1 ulp < sqrt(x) - z < 1.0625 ulp
+            instead of |sqrt(x)-z|<1.03125ulp.
+
+    (3) Final adjustment
+
+        By twiddling y's last bit it is possible to force y to be 
+        correctly rounded according to the prevailing rounding mode
+        as follows. Let r and i be copies of the rounding mode and
+        inexact flag before entering the square root program. Also we
+        use the expression y+-ulp for the next representable floating
+        numbers (up and down) of y. Note that y+-ulp = either fixed
+        point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+        mode.
+
+        R := RZ;                ... set rounding mode to round-toward-zero
+        switch(r) {
+            case RN:            ... round-to-nearest
+               if(x<= z*(z-ulp)...chopped) z = z - ulp; else
+               if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp;
+               break;
+            case RZ:case RM:    ... round-to-zero or round-to--inf
+               R:=RP;           ... reset rounding mod to round-to-+inf
+               if(x<z*z ... rounded up) z = z - ulp; else
+               if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp;
+               break;
+            case RP:            ... round-to-+inf
+               if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else
+               if(x>z*z ...chopped) z = z+ulp;
+               break;
+        }
+
+        Remark 3. The above comparisons can be done in fixed point. For
+        example, to compare x and w=z*z chopped, it suffices to compare
+        x1 and w1 (the trailing parts of x and w), regarding them as
+        two's complement integers.
+
+        ...Is z an exact square root?
+        To determine whether z is an exact square root of x, let z1 be the
+        trailing part of z, and also let x0 and x1 be the leading and
+        trailing parts of x.
+
+        If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0
+            I := 1;             ... Raise Inexact flag: z is not exact
+        else {
+            j := 1 - [(x0>>20)&1]       ... j = logb(x) mod 2
+            k := z1 >> 26;              ... get z's 25-th and 26-th 
+                                            fraction bits
+            I := i or (k&j) or ((k&(j+j+1))!=(x1&3));
+        }
+        R:= r           ... restore rounded mode
+        return sqrt(x):=z.
+
+        If multiplication is cheaper then the foregoing red tape, the 
+        Inexact flag can be evaluated by
+
+            I := i;
+            I := (z*z!=x) or I.
+
+        Note that z*z can overwrite I; this value must be sensed if it is 
+        True.
+
+        Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be
+        zero.
+
+                    --------------------
+                z1: |        f2        | 
+                    --------------------
+                bit 31             bit 0
+
+        Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd
+        or even of logb(x) have the following relations:
+
+        -------------------------------------------------
+        bit 27,26 of z1         bit 1,0 of x1   logb(x)
+        -------------------------------------------------
+        00                      00              odd and even
+        01                      01              even
+        10                      10              odd
+        10                      00              even
+        11                      01              even
+        -------------------------------------------------
+
+    (4) Special cases (see (4) of Section A).   
+ 
+ */
+ 
diff --git a/src/math/e_sqrtf.c b/src/math/e_sqrtf.c
new file mode 100644
index 00000000..03a15beb
--- /dev/null
+++ b/src/math/e_sqrtf.c
@@ -0,0 +1,85 @@
+/* e_sqrtf.c -- float version of e_sqrt.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 <math.h>
+#include "math_private.h"
+
+static  const float     one     = 1.0, tiny=1.0e-30;
+
+float
+sqrtf(float x)
+{
+        float z;
+        int32_t sign = (int)0x80000000;
+        int32_t ix,s,q,m,t,i;
+        uint32_t r;
+
+        GET_FLOAT_WORD(ix,x);
+
+    /* take care of Inf and NaN */
+        if((ix&0x7f800000)==0x7f800000) {
+            return x*x+x;               /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+                                           sqrt(-inf)=sNaN */
+        }
+    /* take care of zero */
+        if(ix<=0) {
+            if((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */
+            else if(ix<0)
+                return (x-x)/(x-x);             /* sqrt(-ve) = sNaN */
+        }
+    /* normalize x */
+        m = (ix>>23);
+        if(m==0) {                              /* subnormal x */
+            for(i=0;(ix&0x00800000)==0;i++) ix<<=1;
+            m -= i-1;
+        }
+        m -= 127;       /* unbias exponent */
+        ix = (ix&0x007fffff)|0x00800000;
+        if(m&1) /* odd m, double x to make it even */
+            ix += ix;
+        m >>= 1;        /* m = [m/2] */
+
+    /* generate sqrt(x) bit by bit */
+        ix += ix;
+        q = s = 0;              /* q = sqrt(x) */
+        r = 0x01000000;         /* r = moving bit from right to left */
+
+        while(r!=0) {
+            t = s+r;
+            if(t<=ix) {
+                s    = t+r;
+                ix  -= t;
+                q   += r;
+            }
+            ix += ix;
+            r>>=1;
+        }
+
+    /* use floating add to find out rounding direction */
+        if(ix!=0) {
+            z = one-tiny; /* trigger inexact flag */
+            if (z>=one) {
+                z = one+tiny;
+                if (z>one)
+                    q += 2;
+                else
+                    q += (q&1);
+            }
+        }
+        ix = (q>>1)+0x3f000000;
+        ix += (m <<23);
+        SET_FLOAT_WORD(z,ix);
+        return z;
+}
diff --git a/src/math/i386/e_exp.s b/src/math/i386/e_exp.s
new file mode 100644
index 00000000..d6c54a30
--- /dev/null
+++ b/src/math/i386/e_exp.s
@@ -0,0 +1,36 @@
+.global expf
+expf:
+	mov 4(%esp),%eax
+	flds 4(%esp)
+	shr $23,%eax
+	inc %al
+	jz 1f
+	jmp 0f
+
+.global exp
+exp:
+	mov 8(%esp),%eax
+	fldl 4(%esp)
+	shl %eax
+	cmp $0xffe00000,%eax
+	jae 1f
+
+0:	fldl2e
+	fmulp
+	fst %st(1)
+	frndint
+	fst %st(2)
+	fsubrp
+	f2xm1
+	fld1
+	faddp
+	fscale
+	fstp %st(1)
+	ret
+
+1:	fsts 4(%esp)
+	cmpl $0xff800000,4(%esp)
+	jnz 1f
+	fstp %st(0)
+	fldz
+1:	ret
diff --git a/src/math/i386/e_expf.s b/src/math/i386/e_expf.s
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/src/math/i386/e_expf.s
@@ -0,0 +1 @@
+
diff --git a/src/math/i386/e_log.s b/src/math/i386/e_log.s
new file mode 100644
index 00000000..34b8d38d
--- /dev/null
+++ b/src/math/i386/e_log.s
@@ -0,0 +1,6 @@
+.global log
+log:
+	fldln2
+	fldl 4(%esp)
+	fyl2x
+	ret
diff --git a/src/math/i386/e_log10.s b/src/math/i386/e_log10.s
new file mode 100644
index 00000000..7f48941b
--- /dev/null
+++ b/src/math/i386/e_log10.s
@@ -0,0 +1,6 @@
+.global log10
+log10:
+	fldlg2
+	fldl 4(%esp)
+	fyl2x
+	ret
diff --git a/src/math/i386/e_log10f.s b/src/math/i386/e_log10f.s
new file mode 100644
index 00000000..311486ea
--- /dev/null
+++ b/src/math/i386/e_log10f.s
@@ -0,0 +1,6 @@
+.global log10f
+log10f:
+	fldlg2
+	flds 4(%esp)
+	fyl2x
+	ret
diff --git a/src/math/i386/e_logf.s b/src/math/i386/e_logf.s
new file mode 100644
index 00000000..b8beec0f
--- /dev/null
+++ b/src/math/i386/e_logf.s
@@ -0,0 +1,6 @@
+.global logf
+logf:
+	fldln2
+	flds 4(%esp)
+	fyl2x
+	ret
diff --git a/src/math/i386/e_remainder.s b/src/math/i386/e_remainder.s
new file mode 100644
index 00000000..b7ff3ef8
--- /dev/null
+++ b/src/math/i386/e_remainder.s
@@ -0,0 +1,16 @@
+.global remainderf
+remainderf:
+	flds 8(%esp)
+	flds 4(%esp)
+	jmp 1f
+	
+.global remainder
+remainder:
+	fldl 12(%esp)
+	fldl 4(%esp)
+1:	fprem1
+	fstsw %ax
+	sahf
+	jp 1b
+	fstp %st(1)
+	ret
diff --git a/src/math/i386/e_remainderf.s b/src/math/i386/e_remainderf.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/e_remainderf.s
diff --git a/src/math/i386/e_sqrt.s b/src/math/i386/e_sqrt.s
new file mode 100644
index 00000000..11314dca
--- /dev/null
+++ b/src/math/i386/e_sqrt.s
@@ -0,0 +1,4 @@
+.global sqrt
+sqrt:	fldl 4(%esp)
+	fsqrt
+	ret
diff --git a/src/math/i386/e_sqrtf.s b/src/math/i386/e_sqrtf.s
new file mode 100644
index 00000000..015e24cd
--- /dev/null
+++ b/src/math/i386/e_sqrtf.s
@@ -0,0 +1,4 @@
+.global sqrtf
+sqrtf:	flds 4(%esp)
+	fsqrt
+	ret
diff --git a/src/math/i386/s_ceil.s b/src/math/i386/s_ceil.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_ceil.s
diff --git a/src/math/i386/s_ceilf.s b/src/math/i386/s_ceilf.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_ceilf.s
diff --git a/src/math/i386/s_fabs.s b/src/math/i386/s_fabs.s
new file mode 100644
index 00000000..10c70f37
--- /dev/null
+++ b/src/math/i386/s_fabs.s
@@ -0,0 +1,5 @@
+.global fabs
+fabs:
+	fldl 4(%esp)
+	fabs
+	ret
diff --git a/src/math/i386/s_fabsf.s b/src/math/i386/s_fabsf.s
new file mode 100644
index 00000000..45442699
--- /dev/null
+++ b/src/math/i386/s_fabsf.s
@@ -0,0 +1,5 @@
+.global fabsf
+fabsf:
+	flds 4(%esp)
+	fabs
+	ret
diff --git a/src/math/i386/s_floor.s b/src/math/i386/s_floor.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_floor.s
diff --git a/src/math/i386/s_floorf.s b/src/math/i386/s_floorf.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_floorf.s
diff --git a/src/math/i386/s_ldexp.s b/src/math/i386/s_ldexp.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_ldexp.s
diff --git a/src/math/i386/s_ldexpf.s b/src/math/i386/s_ldexpf.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_ldexpf.s
diff --git a/src/math/i386/s_rint.s b/src/math/i386/s_rint.s
new file mode 100644
index 00000000..5ba4ab4a
--- /dev/null
+++ b/src/math/i386/s_rint.s
@@ -0,0 +1,5 @@
+.global rint
+rint:
+	fldl 4(%esp)
+	frndint
+	ret
diff --git a/src/math/i386/s_rintf.s b/src/math/i386/s_rintf.s
new file mode 100644
index 00000000..d7aacd8f
--- /dev/null
+++ b/src/math/i386/s_rintf.s
@@ -0,0 +1,5 @@
+.global rintf
+rintf:
+	flds 4(%esp)
+	frndint
+	ret
diff --git a/src/math/i386/s_scalbln.s b/src/math/i386/s_scalbln.s
new file mode 100644
index 00000000..bd022b46
--- /dev/null
+++ b/src/math/i386/s_scalbln.s
@@ -0,0 +1,11 @@
+.global ldexp
+.global scalbn
+.global scalbln
+ldexp:
+scalbn:
+scalbln:
+	fildl 12(%esp)
+	fldl 4(%esp)
+	fscale
+	fstp %st(1)
+	ret
diff --git a/src/math/i386/s_scalblnf.s b/src/math/i386/s_scalblnf.s
new file mode 100644
index 00000000..379ec919
--- /dev/null
+++ b/src/math/i386/s_scalblnf.s
@@ -0,0 +1,11 @@
+.global ldexpf
+.global scalbnf
+.global scalblnf
+ldexpf:
+scalbnf:
+scalblnf:
+	fildl 8(%esp)
+	flds 4(%esp)
+	fscale
+	fstp %st(1)
+	ret
diff --git a/src/math/i386/s_trunc.s b/src/math/i386/s_trunc.s
new file mode 100644
index 00000000..0773891a
--- /dev/null
+++ b/src/math/i386/s_trunc.s
@@ -0,0 +1,36 @@
+.global ceilf
+ceilf:	flds 4(%esp)
+	jmp 1f
+	
+.global ceil
+ceil:	fldl 4(%esp)
+1:	mov $0x08fb,%edx
+	jmp 0f
+
+.global floorf
+floorf:	flds 4(%esp)
+	jmp 1f
+
+.global floor
+floor:	fldl 4(%esp)
+1:	mov $0x04f7,%edx
+	jmp 0f
+
+.global truncf
+truncf:	flds 4(%esp)
+	jmp 1f
+
+.global trunc
+trunc:	fldl 4(%esp)
+1:	mov $0x0cff,%edx
+
+0:	fstcw 4(%esp)
+	mov 5(%esp),%ah
+	or %dh,%ah
+	and %dl,%ah
+	xchg %ah,5(%esp)
+	fldcw 4(%esp)
+	frndint
+	mov %ah,5(%esp)
+	fldcw 4(%esp)
+	ret
diff --git a/src/math/i386/s_truncf.s b/src/math/i386/s_truncf.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_truncf.s
diff --git a/src/math/k_cos.c b/src/math/k_cos.c
new file mode 100644
index 00000000..22e9841e
--- /dev/null
+++ b/src/math/k_cos.c
@@ -0,0 +1,85 @@
+
+/* @(#)k_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_cos( x,  y )
+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x. 
+ *
+ * Algorithm
+ *      1. Since cos(-x) = cos(x), we need only to consider positive x.
+ *      2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
+ *      3. cos(x) is approximated by a polynomial of degree 14 on
+ *         [0,pi/4]
+ *                                       4            14
+ *              cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+ *         where the remez error is
+ *      
+ *      |              2     4     6     8     10    12     14 |     -58
+ *      |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2
+ *      |                                                      | 
+ * 
+ *                     4     6     8     10    12     14 
+ *      4. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then
+ *             cos(x) = 1 - x*x/2 + r
+ *         since cos(x+y) ~ cos(x) - sin(x)*y 
+ *                        ~ cos(x) - x*y,
+ *         a correction term is necessary in cos(x) and hence
+ *              cos(x+y) = 1 - (x*x/2 - (r - x*y))
+ *         For better accuracy when x > 0.3, let qx = |x|/4 with
+ *         the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
+ *         Then
+ *              cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)).
+ *         Note that 1-qx and (x*x/2-qx) is EXACT here, and the
+ *         magnitude of the latter is at least a quarter of x*x/2,
+ *         thus, reducing the rounding error in the subtraction.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+C1  =  4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2  = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3  =  2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4  = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5  =  2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6  = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+double
+__kernel_cos(double x, double y)
+{
+        double a,hz,z,r,qx;
+        int32_t ix;
+        GET_HIGH_WORD(ix,x);
+        ix &= 0x7fffffff;                       /* ix = |x|'s high word*/
+        if(ix<0x3e400000) {                     /* if x < 2**27 */
+            if(((int)x)==0) return one;         /* generate inexact */
+        }
+        z  = x*x;
+        r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+        if(ix < 0x3FD33333)                     /* if |x| < 0.3 */ 
+            return one - (0.5*z - (z*r - x*y));
+        else {
+            if(ix > 0x3fe90000) {               /* x > 0.78125 */
+                qx = 0.28125;
+            } else {
+                INSERT_WORDS(qx,ix-0x00200000,0);       /* x/4 */
+            }
+            hz = 0.5*z-qx;
+            a  = one-qx;
+            return a - (hz - (z*r-x*y));
+        }
+}
diff --git a/src/math/k_cosf.c b/src/math/k_cosf.c
new file mode 100644
index 00000000..61dc3749
--- /dev/null
+++ b/src/math/k_cosf.c
@@ -0,0 +1,52 @@
+/* k_cosf.c -- float version of k_cos.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 <math.h>
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3f800000 */
+C1  =  4.1666667908e-02, /* 0x3d2aaaab */
+C2  = -1.3888889225e-03, /* 0xbab60b61 */
+C3  =  2.4801587642e-05, /* 0x37d00d01 */
+C4  = -2.7557314297e-07, /* 0xb493f27c */
+C5  =  2.0875723372e-09, /* 0x310f74f6 */
+C6  = -1.1359647598e-11; /* 0xad47d74e */
+
+float
+__kernel_cosf(float x, float y)
+{
+        float a,hz,z,r,qx;
+        int32_t ix;
+        GET_FLOAT_WORD(ix,x);
+        ix &= 0x7fffffff;                       /* ix = |x|'s high word*/
+        if(ix<0x32000000) {                     /* if x < 2**27 */
+            if(((int)x)==0) return one;         /* generate inexact */
+        }
+        z  = x*x;
+        r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+        if(ix < 0x3e99999a)                     /* if |x| < 0.3 */
+            return one - ((float)0.5*z - (z*r - x*y));
+        else {
+            if(ix > 0x3f480000) {               /* x > 0.78125 */
+                qx = (float)0.28125;
+            } else {
+                SET_FLOAT_WORD(qx,ix-0x01000000);       /* x/4 */
+            }
+            hz = (float)0.5*z-qx;
+            a  = one-qx;
+            return a - (hz - (z*r-x*y));
+        }
+}
diff --git a/src/math/k_rem_pio2.c b/src/math/k_rem_pio2.c
new file mode 100644
index 00000000..d993e4f2
--- /dev/null
+++ b/src/math/k_rem_pio2.c
@@ -0,0 +1,300 @@
+
+/* @(#)k_rem_pio2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ * double x[],y[]; int e0,nx,prec; int ipio2[];
+ * 
+ * __kernel_rem_pio2 return the last three digits of N with 
+ *              y = x - N*pi/2
+ * so that |y| < pi/2.
+ *
+ * The method is to compute the integer (mod 8) and fraction parts of 
+ * (2/pi)*x without doing the full multiplication. In general we
+ * skip the part of the product that are known to be a huge integer (
+ * more accurately, = 0 mod 8 ). Thus the number of operations are
+ * independent of the exponent of the input.
+ *
+ * (2/pi) is represented by an array of 24-bit integers in ipio2[].
+ *
+ * Input parameters:
+ *      x[]     The input value (must be positive) is broken into nx 
+ *              pieces of 24-bit integers in double precision format.
+ *              x[i] will be the i-th 24 bit of x. The scaled exponent 
+ *              of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 
+ *              match x's up to 24 bits.
+ *
+ *              Example of breaking a double positive z into x[0]+x[1]+x[2]:
+ *                      e0 = ilogb(z)-23
+ *                      z  = scalbn(z,-e0)
+ *              for i = 0,1,2
+ *                      x[i] = floor(z)
+ *                      z    = (z-x[i])*2**24
+ *
+ *
+ *      y[]     ouput result in an array of double precision numbers.
+ *              The dimension of y[] is:
+ *                      24-bit  precision       1
+ *                      53-bit  precision       2
+ *                      64-bit  precision       2
+ *                      113-bit precision       3
+ *              The actual value is the sum of them. Thus for 113-bit
+ *              precison, one may have to do something like:
+ *
+ *              long double t,w,r_head, r_tail;
+ *              t = (long double)y[2] + (long double)y[1];
+ *              w = (long double)y[0];
+ *              r_head = t+w;
+ *              r_tail = w - (r_head - t);
+ *
+ *      e0      The exponent of x[0]
+ *
+ *      nx      dimension of x[]
+ *
+ *      prec    an integer indicating the precision:
+ *                      0       24  bits (single)
+ *                      1       53  bits (double)
+ *                      2       64  bits (extended)
+ *                      3       113 bits (quad)
+ *
+ *      ipio2[]
+ *              integer array, contains the (24*i)-th to (24*i+23)-th 
+ *              bit of 2/pi after binary point. The corresponding 
+ *              floating value is
+ *
+ *                      ipio2[i] * 2^(-24(i+1)).
+ *
+ * External function:
+ *      double scalbn(), floor();
+ *
+ *
+ * Here is the description of some local variables:
+ *
+ *      jk      jk+1 is the initial number of terms of ipio2[] needed
+ *              in the computation. The recommended value is 2,3,4,
+ *              6 for single, double, extended,and quad.
+ *
+ *      jz      local integer variable indicating the number of 
+ *              terms of ipio2[] used. 
+ *
+ *      jx      nx - 1
+ *
+ *      jv      index for pointing to the suitable ipio2[] for the
+ *              computation. In general, we want
+ *                      ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
+ *              is an integer. Thus
+ *                      e0-3-24*jv >= 0 or (e0-3)/24 >= jv
+ *              Hence jv = max(0,(e0-3)/24).
+ *
+ *      jp      jp+1 is the number of terms in PIo2[] needed, jp = jk.
+ *
+ *      q[]     double array with integral value, representing the
+ *              24-bits chunk of the product of x and 2/pi.
+ *
+ *      q0      the corresponding exponent of q[0]. Note that the
+ *              exponent for q[i] would be q0-24*i.
+ *
+ *      PIo2[]  double precision array, obtained by cutting pi/2
+ *              into 24 bits chunks. 
+ *
+ *      f[]     ipio2[] in floating point 
+ *
+ *      iq[]    integer array by breaking up q[] in 24-bits chunk.
+ *
+ *      fq[]    final product of x*(2/pi) in fq[0],..,fq[jk]
+ *
+ *      ih      integer. If >0 it indicates q[] is >= 0.5, hence
+ *              it also indicates the *sign* of the result.
+ *
+ */
+
+
+/*
+ * 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 <math.h>
+#include "math_private.h"
+
+static const int init_jk[] = {2,3,4,6}; /* initial value for jk */
+
+static const double PIo2[] = {
+  1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
+  7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
+  5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
+  3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
+  1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
+  1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
+  2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
+  2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
+};
+
+static const double                     
+zero   = 0.0,
+one    = 1.0,
+two24   =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+twon24  =  5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
+
+        int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int32_t *ipio2)
+{
+        int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+        double z,fw,f[20],fq[20],q[20];
+
+    /* initialize jk*/
+        jk = init_jk[prec];
+        jp = jk;
+
+    /* determine jx,jv,q0, note that 3>q0 */
+        jx =  nx-1;
+        jv = (e0-3)/24; if(jv<0) jv=0;
+        q0 =  e0-24*(jv+1);
+
+    /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+        j = jv-jx; m = jx+jk;
+        for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j];
+
+    /* compute q[0],q[1],...q[jk] */
+        for (i=0;i<=jk;i++) {
+            for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+        }
+
+        jz = jk;
+recompute:
+    /* distill q[] into iq[] reversingly */
+        for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+            fw    =  (double)((int32_t)(twon24* z));
+            iq[i] =  (int32_t)(z-two24*fw);
+            z     =  q[j-1]+fw;
+        }
+
+    /* compute n */
+        z  = scalbn(z,q0);              /* actual value of z */
+        z -= 8.0*floor(z*0.125);                /* trim off integer >= 8 */
+        n  = (int32_t) z;
+        z -= (double)n;
+        ih = 0;
+        if(q0>0) {      /* need iq[jz-1] to determine n */
+            i  = (iq[jz-1]>>(24-q0)); n += i;
+            iq[jz-1] -= i<<(24-q0);
+            ih = iq[jz-1]>>(23-q0);
+        } 
+        else if(q0==0) ih = iq[jz-1]>>23;
+        else if(z>=0.5) ih=2;
+
+        if(ih>0) {      /* q > 0.5 */
+            n += 1; carry = 0;
+            for(i=0;i<jz ;i++) {        /* compute 1-q */
+                j = iq[i];
+                if(carry==0) {
+                    if(j!=0) {
+                        carry = 1; iq[i] = 0x1000000- j;
+                    }
+                } else  iq[i] = 0xffffff - j;
+            }
+            if(q0>0) {          /* rare case: chance is 1 in 12 */
+                switch(q0) {
+                case 1:
+                   iq[jz-1] &= 0x7fffff; break;
+                case 2:
+                   iq[jz-1] &= 0x3fffff; break;
+                }
+            }
+            if(ih==2) {
+                z = one - z;
+                if(carry!=0) z -= scalbn(one,q0);
+            }
+        }
+
+    /* check if recomputation is needed */
+        if(z==zero) {
+            j = 0;
+            for (i=jz-1;i>=jk;i--) j |= iq[i];
+            if(j==0) { /* need recomputation */
+                for(k=1;iq[jk-k]==0;k++);   /* k = no. of terms needed */
+
+                for(i=jz+1;i<=jz+k;i++) {   /* add q[jz+1] to q[jz+k] */
+                    f[jx+i] = (double) ipio2[jv+i];
+                    for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+                    q[i] = fw;
+                }
+                jz += k;
+                goto recompute;
+            }
+        }
+
+    /* chop off zero terms */
+        if(z==0.0) {
+            jz -= 1; q0 -= 24;
+            while(iq[jz]==0) { jz--; q0-=24;}
+        } else { /* break z into 24-bit if necessary */
+            z = scalbn(z,-q0);
+            if(z>=two24) { 
+                fw = (double)((int32_t)(twon24*z));
+                iq[jz] = (int32_t)(z-two24*fw);
+                jz += 1; q0 += 24;
+                iq[jz] = (int32_t) fw;
+            } else iq[jz] = (int32_t) z ;
+        }
+
+    /* convert integer "bit" chunk to floating-point value */
+        fw = scalbn(one,q0);
+        for(i=jz;i>=0;i--) {
+            q[i] = fw*(double)iq[i]; fw*=twon24;
+        }
+
+    /* compute PIo2[0,...,jp]*q[jz,...,0] */
+        for(i=jz;i>=0;i--) {
+            for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+            fq[jz-i] = fw;
+        }
+
+    /* compress fq[] into y[] */
+        switch(prec) {
+            case 0:
+                fw = 0.0;
+                for (i=jz;i>=0;i--) fw += fq[i];
+                y[0] = (ih==0)? fw: -fw; 
+                break;
+            case 1:
+            case 2:
+                fw = 0.0;
+                for (i=jz;i>=0;i--) fw += fq[i]; 
+                y[0] = (ih==0)? fw: -fw; 
+                fw = fq[0]-fw;
+                for (i=1;i<=jz;i++) fw += fq[i];
+                y[1] = (ih==0)? fw: -fw; 
+                break;
+            case 3:     /* painful */
+                for (i=jz;i>0;i--) {
+                    fw      = fq[i-1]+fq[i]; 
+                    fq[i]  += fq[i-1]-fw;
+                    fq[i-1] = fw;
+                }
+                for (i=jz;i>1;i--) {
+                    fw      = fq[i-1]+fq[i]; 
+                    fq[i]  += fq[i-1]-fw;
+                    fq[i-1] = fw;
+                }
+                for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; 
+                if(ih==0) {
+                    y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw;
+                } else {
+                    y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+                }
+        }
+        return n&7;
+}
diff --git a/src/math/k_rem_pio2f.c b/src/math/k_rem_pio2f.c
new file mode 100644
index 00000000..b543f084
--- /dev/null
+++ b/src/math/k_rem_pio2f.c
@@ -0,0 +1,192 @@
+/* k_rem_pio2f.c -- float version of k_rem_pio2.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 <math.h>
+#include "math_private.h"
+
+/* In the float version, the input parameter x contains 8 bit
+   integers, not 24 bit integers.  113 bit precision is not supported.  */
+
+static const int init_jk[] = {4,7,9}; /* initial value for jk */
+
+static const float PIo2[] = {
+  1.5703125000e+00, /* 0x3fc90000 */
+  4.5776367188e-04, /* 0x39f00000 */
+  2.5987625122e-05, /* 0x37da0000 */
+  7.5437128544e-08, /* 0x33a20000 */
+  6.0026650317e-11, /* 0x2e840000 */
+  7.3896444519e-13, /* 0x2b500000 */
+  5.3845816694e-15, /* 0x27c20000 */
+  5.6378512969e-18, /* 0x22d00000 */
+  8.3009228831e-20, /* 0x1fc40000 */
+  3.2756352257e-22, /* 0x1bc60000 */
+  6.3331015649e-25, /* 0x17440000 */
+};
+
+static const float
+zero   = 0.0,
+one    = 1.0,
+two8   =  2.5600000000e+02, /* 0x43800000 */
+twon8  =  3.9062500000e-03; /* 0x3b800000 */
+
+        int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const int32_t *ipio2)
+{
+        int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+        float z,fw,f[20],fq[20],q[20];
+
+    /* initialize jk*/
+        jk = init_jk[prec];
+        jp = jk;
+
+    /* determine jx,jv,q0, note that 3>q0 */
+        jx =  nx-1;
+        jv = (e0-3)/8; if(jv<0) jv=0;
+        q0 =  e0-8*(jv+1);
+
+    /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+        j = jv-jx; m = jx+jk;
+        for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j];
+
+    /* compute q[0],q[1],...q[jk] */
+        for (i=0;i<=jk;i++) {
+            for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+        }
+
+        jz = jk;
+recompute:
+    /* distill q[] into iq[] reversingly */
+        for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+            fw    =  (float)((int32_t)(twon8* z));
+            iq[i] =  (int32_t)(z-two8*fw);
+            z     =  q[j-1]+fw;
+        }
+
+    /* compute n */
+        z  = scalbnf(z,q0);             /* actual value of z */
+        z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */
+        n  = (int32_t) z;
+        z -= (float)n;
+        ih = 0;
+        if(q0>0) {      /* need iq[jz-1] to determine n */
+            i  = (iq[jz-1]>>(8-q0)); n += i;
+            iq[jz-1] -= i<<(8-q0);
+            ih = iq[jz-1]>>(7-q0);
+        }
+        else if(q0==0) ih = iq[jz-1]>>7;
+        else if(z>=(float)0.5) ih=2;
+
+        if(ih>0) {      /* q > 0.5 */
+            n += 1; carry = 0;
+            for(i=0;i<jz ;i++) {        /* compute 1-q */
+                j = iq[i];
+                if(carry==0) {
+                    if(j!=0) {
+                        carry = 1; iq[i] = 0x100- j;
+                    }
+                } else  iq[i] = 0xff - j;
+            }
+            if(q0>0) {          /* rare case: chance is 1 in 12 */
+                switch(q0) {
+                case 1:
+                   iq[jz-1] &= 0x7f; break;
+                case 2:
+                   iq[jz-1] &= 0x3f; break;
+                }
+            }
+            if(ih==2) {
+                z = one - z;
+                if(carry!=0) z -= scalbnf(one,q0);
+            }
+        }
+
+    /* check if recomputation is needed */
+        if(z==zero) {
+            j = 0;
+            for (i=jz-1;i>=jk;i--) j |= iq[i];
+            if(j==0) { /* need recomputation */
+                for(k=1;iq[jk-k]==0;k++);   /* k = no. of terms needed */
+
+                for(i=jz+1;i<=jz+k;i++) {   /* add q[jz+1] to q[jz+k] */
+                    f[jx+i] = (float) ipio2[jv+i];
+                    for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+                    q[i] = fw;
+                }
+                jz += k;
+                goto recompute;
+            }
+        }
+
+    /* chop off zero terms */
+        if(z==(float)0.0) {
+            jz -= 1; q0 -= 8;
+            while(iq[jz]==0) { jz--; q0-=8;}
+        } else { /* break z into 8-bit if necessary */
+            z = scalbnf(z,-q0);
+            if(z>=two8) {
+                fw = (float)((int32_t)(twon8*z));
+                iq[jz] = (int32_t)(z-two8*fw);
+                jz += 1; q0 += 8;
+                iq[jz] = (int32_t) fw;
+            } else iq[jz] = (int32_t) z ;
+        }
+
+    /* convert integer "bit" chunk to floating-point value */
+        fw = scalbnf(one,q0);
+        for(i=jz;i>=0;i--) {
+            q[i] = fw*(float)iq[i]; fw*=twon8;
+        }
+
+    /* compute PIo2[0,...,jp]*q[jz,...,0] */
+        for(i=jz;i>=0;i--) {
+            for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+            fq[jz-i] = fw;
+        }
+
+    /* compress fq[] into y[] */
+        switch(prec) {
+            case 0:
+                fw = 0.0;
+                for (i=jz;i>=0;i--) fw += fq[i];
+                y[0] = (ih==0)? fw: -fw;
+                break;
+            case 1:
+            case 2:
+                fw = 0.0;
+                for (i=jz;i>=0;i--) fw += fq[i];
+                y[0] = (ih==0)? fw: -fw;
+                fw = fq[0]-fw;
+                for (i=1;i<=jz;i++) fw += fq[i];
+                y[1] = (ih==0)? fw: -fw;
+                break;
+            case 3:     /* painful */
+                for (i=jz;i>0;i--) {
+                    fw      = fq[i-1]+fq[i];
+                    fq[i]  += fq[i-1]-fw;
+                    fq[i-1] = fw;
+                }
+                for (i=jz;i>1;i--) {
+                    fw      = fq[i-1]+fq[i];
+                    fq[i]  += fq[i-1]-fw;
+                    fq[i-1] = fw;
+                }
+                for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
+                if(ih==0) {
+                    y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw;
+                } else {
+                    y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+                }
+        }
+        return n&7;
+}
diff --git a/src/math/k_sin.c b/src/math/k_sin.c
new file mode 100644
index 00000000..9def2589
--- /dev/null
+++ b/src/math/k_sin.c
@@ -0,0 +1,68 @@
+
+/* @(#)k_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_sin( x, y, iy)
+ * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). 
+ *
+ * Algorithm
+ *      1. Since sin(-x) = -sin(x), we need only to consider positive x. 
+ *      2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0.
+ *      3. sin(x) is approximated by a polynomial of degree 13 on
+ *         [0,pi/4]
+ *                               3            13
+ *              sin(x) ~ x + S1*x + ... + S6*x
+ *         where
+ *      
+ *      |sin(x)         2     4     6     8     10     12  |     -58
+ *      |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x  +S6*x   )| <= 2
+ *      |  x                                               | 
+ * 
+ *      4. sin(x+y) = sin(x) + sin'(x')*y
+ *                  ~ sin(x) + (1-x*x/2)*y
+ *         For better accuracy, let 
+ *                   3      2      2      2      2
+ *              r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
+ *         then                   3    2
+ *              sin(x) = x + (S1*x + (x *(r-y/2)+y))
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+S1  = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2  =  8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3  = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4  =  2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5  = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6  =  1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
+
+double
+__kernel_sin(double x, double y, int iy)
+{
+        double z,r,v;
+        int32_t ix;
+        GET_HIGH_WORD(ix,x);
+        ix &= 0x7fffffff;                       /* high word of x */
+        if(ix<0x3e400000)                       /* |x| < 2**-27 */
+           {if((int)x==0) return x;}            /* generate inexact */
+        z       =  x*x;
+        v       =  z*x;
+        r       =  S2+z*(S3+z*(S4+z*(S5+z*S6)));
+        if(iy==0) return x+v*(S1+z*r);
+        else      return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/src/math/k_sinf.c b/src/math/k_sinf.c
new file mode 100644
index 00000000..617f6148
--- /dev/null
+++ b/src/math/k_sinf.c
@@ -0,0 +1,42 @@
+/* k_sinf.c -- float version of k_sin.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 <math.h>
+#include "math_private.h"
+
+static const float
+half =  5.0000000000e-01,/* 0x3f000000 */
+S1  = -1.6666667163e-01, /* 0xbe2aaaab */
+S2  =  8.3333337680e-03, /* 0x3c088889 */
+S3  = -1.9841270114e-04, /* 0xb9500d01 */
+S4  =  2.7557314297e-06, /* 0x3638ef1b */
+S5  = -2.5050759689e-08, /* 0xb2d72f34 */
+S6  =  1.5896910177e-10; /* 0x2f2ec9d3 */
+
+float
+__kernel_sinf(float x, float y, int iy)
+{
+        float z,r,v;
+        int32_t ix;
+        GET_FLOAT_WORD(ix,x);
+        ix &= 0x7fffffff;                       /* high word of x */
+        if(ix<0x32000000)                       /* |x| < 2**-27 */
+           {if((int)x==0) return x;}            /* generate inexact */
+        z       =  x*x;
+        v       =  z*x;
+        r       =  S2+z*(S3+z*(S4+z*(S5+z*S6)));
+        if(iy==0) return x+v*(S1+z*r);
+        else      return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/src/math/k_tan.c b/src/math/k_tan.c
new file mode 100644
index 00000000..f721ae6d
--- /dev/null
+++ b/src/math/k_tan.c
@@ -0,0 +1,149 @@
+/* @(#)k_tan.c 1.5 04/04/22 SMI */
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_tan( x, y, k )
+ * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned.
+ *
+ * Algorithm
+ *      1. Since tan(-x) = -tan(x), we need only to consider positive x.
+ *      2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
+ *      3. tan(x) is approximated by a odd polynomial of degree 27 on
+ *         [0,0.67434]
+ *                               3             27
+ *              tan(x) ~ x + T1*x + ... + T13*x
+ *         where
+ *
+ *              |tan(x)         2     4            26   |     -59.2
+ *              |----- - (1+T1*x +T2*x +.... +T13*x    )| <= 2
+ *              |  x                                    |
+ *
+ *         Note: tan(x+y) = tan(x) + tan'(x)*y
+ *                        ~ tan(x) + (1+x*x)*y
+ *         Therefore, for better accuracy in computing tan(x+y), let
+ *                   3      2      2       2       2
+ *              r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+ *         then
+ *                                  3    2
+ *              tan(x+y) = x + (T1*x + (x *(r+y)+y))
+ *
+ *      4. For x in [0.67434,pi/4],  let y = pi/4 - x, then
+ *              tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
+ *                     = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
+ */
+
+#include <math.h>
+#include "math_private.h"
+static const double xxx[] = {
+                 3.33333333333334091986e-01,    /* 3FD55555, 55555563 */
+                 1.33333333333201242699e-01,    /* 3FC11111, 1110FE7A */
+                 5.39682539762260521377e-02,    /* 3FABA1BA, 1BB341FE */
+                 2.18694882948595424599e-02,    /* 3F9664F4, 8406D637 */
+                 8.86323982359930005737e-03,    /* 3F8226E3, E96E8493 */
+                 3.59207910759131235356e-03,    /* 3F6D6D22, C9560328 */
+                 1.45620945432529025516e-03,    /* 3F57DBC8, FEE08315 */
+                 5.88041240820264096874e-04,    /* 3F4344D8, F2F26501 */
+                 2.46463134818469906812e-04,    /* 3F3026F7, 1A8D1068 */
+                 7.81794442939557092300e-05,    /* 3F147E88, A03792A6 */
+                 7.14072491382608190305e-05,    /* 3F12B80F, 32F0A7E9 */
+                -1.85586374855275456654e-05,    /* BEF375CB, DB605373 */
+                 2.59073051863633712884e-05,    /* 3EFB2A70, 74BF7AD4 */
+/* one */        1.00000000000000000000e+00,    /* 3FF00000, 00000000 */
+/* pio4 */       7.85398163397448278999e-01,    /* 3FE921FB, 54442D18 */
+/* pio4lo */     3.06161699786838301793e-17     /* 3C81A626, 33145C07 */
+};
+#define one     xxx[13]
+#define pio4    xxx[14]
+#define pio4lo  xxx[15]
+#define T       xxx
+/* INDENT ON */
+
+double
+__kernel_tan(double x, double y, int iy) {
+        double z, r, v, w, s;
+        int32_t ix, hx;
+
+        GET_HIGH_WORD(hx,x);
+        ix = hx & 0x7fffffff;                   /* high word of |x| */
+        if (ix < 0x3e300000) {                  /* x < 2**-28 */
+                if ((int) x == 0) {             /* generate inexact */
+                        uint32_t low;
+                        GET_LOW_WORD(low,x);
+                        if (((ix | low) | (iy + 1)) == 0)
+                                return one / fabs(x);
+                        else {
+                                if (iy == 1)
+                                        return x;
+                                else {  /* compute -1 / (x+y) carefully */
+                                        double a, t;
+
+                                        z = w = x + y;
+                                        SET_LOW_WORD(z, 0);
+                                        v = y - (z - x);
+                                        t = a = -one / w;
+                                        SET_LOW_WORD(t, 0);
+                                        s = one + t * z;
+                                        return t + a * (s + t * v);
+                                }
+                        }
+                }
+        }
+        if (ix >= 0x3FE59428) { /* |x| >= 0.6744 */
+                if (hx < 0) {
+                        x = -x;
+                        y = -y;
+                }
+                z = pio4 - x;
+                w = pio4lo - y;
+                x = z + w;
+                y = 0.0;
+        }
+        z = x * x;
+        w = z * z;
+        /*
+         * Break x^5*(T[1]+x^2*T[2]+...) into
+         * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+         * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+         */
+        r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] +
+                w * T[11]))));
+        v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] +
+                w * T[12])))));
+        s = z * x;
+        r = y + z * (s * (r + v) + y);
+        r += T[0] * s;
+        w = x + r;
+        if (ix >= 0x3FE59428) {
+                v = (double) iy;
+                return (double) (1 - ((hx >> 30) & 2)) *
+                        (v - 2.0 * (x - (w * w / (w + v) - r)));
+        }
+        if (iy == 1)
+                return w;
+        else {
+                /*
+                 * if allow error up to 2 ulp, simply return
+                 * -1.0 / (x+r) here
+                 */
+                /* compute -1.0 / (x+r) accurately */
+                double a, t;
+                z = w;
+                SET_LOW_WORD(z,0);
+                v = r - (z - x);        /* z+v = r+x */
+                t = a = -1.0 / w;       /* a = -1.0/w */
+                SET_LOW_WORD(t,0);
+                s = 1.0 + t * z;
+                return t + a * (s + t * v);
+        }
+}
diff --git a/src/math/k_tanf.c b/src/math/k_tanf.c
new file mode 100644
index 00000000..99ede58c
--- /dev/null
+++ b/src/math/k_tanf.c
@@ -0,0 +1,105 @@
+/* k_tanf.c -- float version of k_tan.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+static const float
+one   =  1.0000000000e+00, /* 0x3f800000 */
+pio4  =  7.8539812565e-01, /* 0x3f490fda */
+pio4lo=  3.7748947079e-08, /* 0x33222168 */
+T[] =  {
+  3.3333334327e-01, /* 0x3eaaaaab */
+  1.3333334029e-01, /* 0x3e088889 */
+  5.3968254477e-02, /* 0x3d5d0dd1 */
+  2.1869488060e-02, /* 0x3cb327a4 */
+  8.8632395491e-03, /* 0x3c11371f */
+  3.5920790397e-03, /* 0x3b6b6916 */
+  1.4562094584e-03, /* 0x3abede48 */
+  5.8804126456e-04, /* 0x3a1a26c8 */
+  2.4646313977e-04, /* 0x398137b9 */
+  7.8179444245e-05, /* 0x38a3f445 */
+  7.1407252108e-05, /* 0x3895c07a */
+ -1.8558637748e-05, /* 0xb79bae5f */
+  2.5907305826e-05, /* 0x37d95384 */
+};
+
+float
+__kernel_tanf(float x, float y, int iy)
+{
+        float z,r,v,w,s;
+        int32_t ix,hx;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;     /* high word of |x| */
+        if(ix<0x31800000) {                     /* x < 2**-28 */
+                if ((int) x == 0) {             /* generate inexact */
+                        if ((ix | (iy + 1)) == 0)
+                                return one / fabsf(x);
+                        else {
+                                if (iy == 1)
+                                        return x;
+                                else {  /* compute -1 / (x+y) carefully */
+                                        double a, t;
+
+                                        z = w = x + y;
+                                        GET_FLOAT_WORD(ix, z);
+                                        SET_FLOAT_WORD(z, ix & 0xfffff000);
+                                        v = y - (z - x);
+                                        t = a = -one / w;
+                                        GET_FLOAT_WORD(ix, t);
+                                        SET_FLOAT_WORD(t, ix & 0xfffff000);
+                                        s = one + t * z;
+                                        return t + a * (s + t * v);
+                                }
+                        }
+                }
+        }
+        if(ix>=0x3f2ca140) {                    /* |x|>=0.6744 */
+            if(hx<0) {x = -x; y = -y;}
+            z = pio4-x;
+            w = pio4lo-y;
+            x = z+w; y = 0.0;
+        }
+        z       =  x*x;
+        w       =  z*z;
+    /* Break x^5*(T[1]+x^2*T[2]+...) into
+     *    x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+     *    x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+     */
+        r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11]))));
+        v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12])))));
+        s = z*x;
+        r = y + z*(s*(r+v)+y);
+        r += T[0]*s;
+        w = x+r;
+        if(ix>=0x3f2ca140) {
+            v = (float)iy;
+            return (float)(1-((hx>>30)&2))*(v-(float)2.0*(x-(w*w/(w+v)-r)));
+        }
+        if(iy==1) return w;
+        else {          /* if allow error up to 2 ulp,
+                           simply return -1.0/(x+r) here */
+     /*  compute -1.0/(x+r) accurately */
+            float a,t;
+            int32_t i;
+            z  = w;
+            GET_FLOAT_WORD(i,z);
+            SET_FLOAT_WORD(z,i&0xfffff000);
+            v  = r-(z - x);     /* z+v = r+x */
+            t = a  = -(float)1.0/w;     /* a = -1.0/w */
+            GET_FLOAT_WORD(i,t);
+            SET_FLOAT_WORD(t,i&0xfffff000);
+            s  = (float)1.0+t*z;
+            return t+a*(s+t*v);
+        }
+}
diff --git a/src/math/math_private.h b/src/math/math_private.h
new file mode 100644
index 00000000..28a6a195
--- /dev/null
+++ b/src/math/math_private.h
@@ -0,0 +1,143 @@
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef _MATH_PRIVATE_H_
+#define _MATH_PRIVATE_H_
+
+#include <inttypes.h>
+
+/*
+ * The original fdlibm code used statements like:
+ *      n0 = ((*(int*)&one)>>29)^1;             * index of high word *
+ *      ix0 = *(n0+(int*)&x);                   * high word of x *
+ *      ix1 = *((1-n0)+(int*)&x);               * low word of x *
+ * to dig two 32 bit words out of the 64 bit IEEE floating point
+ * value.  That is non-ANSI, and, moreover, the gcc instruction
+ * scheduler gets it wrong.  We instead use the following macros.
+ * Unlike the original code, we determine the endianness at compile
+ * time, not at run time; I don't see much benefit to selecting
+ * endianness at run time.
+ */
+
+/*
+ * A union which permits us to convert between a double and two 32 bit
+ * ints.
+ */
+
+typedef union
+{
+  double value;
+  uint64_t words;
+} ieee_double_shape_type;
+
+/* Get two 32 bit ints from a double.  */
+
+#define EXTRACT_WORDS(ix0,ix1,d)                                \
+do {                                                            \
+  ieee_double_shape_type ew_u;                                  \
+  ew_u.value = (d);                                             \
+  (ix0) = ew_u.words >> 32;                                     \
+  (ix1) = (uint32_t)ew_u.words;                                 \
+} while (0)
+
+/* Get the more significant 32 bit int from a double.  */
+
+#define GET_HIGH_WORD(i,d)                                      \
+do {                                                            \
+  ieee_double_shape_type gh_u;                                  \
+  gh_u.value = (d);                                             \
+  (i) = gh_u.words >> 32;                                       \
+} while (0)
+
+/* Get the less significant 32 bit int from a double.  */
+
+#define GET_LOW_WORD(i,d)                                       \
+do {                                                            \
+  ieee_double_shape_type gl_u;                                  \
+  gl_u.value = (d);                                             \
+  (i) = (uint32_t)gl_u.words;                                   \
+} while (0)
+
+/* Set a double from two 32 bit ints.  */
+
+#define INSERT_WORDS(d,ix0,ix1)                                 \
+do {                                                            \
+  ieee_double_shape_type iw_u;                                  \
+  iw_u.words = ((uint64_t)(ix0) << 32) | (ix1);                 \
+  (d) = iw_u.value;                                             \
+} while (0)
+
+/* Set the more significant 32 bits of a double from an int.  */
+
+#define SET_HIGH_WORD(d,v)                                      \
+do {                                                            \
+  ieee_double_shape_type sh_u;                                  \
+  sh_u.value = (d);                                             \
+  sh_u.words &= 0xffffffff;                                     \
+  sh_u.words |= ((uint64_t)(v) << 32);                          \
+  (d) = sh_u.value;                                             \
+} while (0)
+
+/* Set the less significant 32 bits of a double from an int.  */
+
+#define SET_LOW_WORD(d,v)                                       \
+do {                                                            \
+  ieee_double_shape_type sl_u;                                  \
+  sl_u.value = (d);                                             \
+  sl_u.words &= 0xffffffff00000000ull;                          \
+  sl_u.words |= (uint32_t)(v);                                  \
+  (d) = sl_u.value;                                             \
+} while (0)
+
+/*
+ * A union which permits us to convert between a float and a 32 bit
+ * int.
+ */
+
+typedef union
+{
+  float value;
+  uint32_t word;
+} ieee_float_shape_type;
+
+/* Get a 32 bit int from a float.  */
+
+#define GET_FLOAT_WORD(i,d)                                     \
+do {                                                            \
+  ieee_float_shape_type gf_u;                                   \
+  gf_u.value = (d);                                             \
+  (i) = gf_u.word;                                              \
+} while (0)
+
+/* Set a float from a 32 bit int.  */
+
+#define SET_FLOAT_WORD(d,i)                                     \
+do {                                                            \
+  ieee_float_shape_type sf_u;                                   \
+  sf_u.word = (i);                                              \
+  (d) = sf_u.value;                                             \
+} while (0)
+
+/* fdlibm kernel function */
+int     __ieee754_rem_pio2(double,double*);
+double  __kernel_sin(double,double,int);
+double  __kernel_cos(double,double);
+double  __kernel_tan(double,double,int);
+int     __kernel_rem_pio2(double*,double*,int,int,int,const int*);
+
+/* float versions of fdlibm kernel functions */
+int     __ieee754_rem_pio2f(float,float*);
+float   __kernel_sinf(float,float,int);
+float   __kernel_cosf(float,float);
+float   __kernel_tanf(float,float,int);
+int     __kernel_rem_pio2f(float*,float*,int,int,int,const int*);
+
+#endif /* !_MATH_PRIVATE_H_ */
diff --git a/src/math/s_asinh.c b/src/math/s_asinh.c
new file mode 100644
index 00000000..26016091
--- /dev/null
+++ b/src/math/s_asinh.c
@@ -0,0 +1,53 @@
+/* @(#)s_asinh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* asinh(x)
+ * Method :
+ *      Based on
+ *              asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+ *      we have
+ *      asinh(x) := x  if  1+x*x=1,
+ *               := sign(x)*(log(x)+ln2)) for large |x|, else
+ *               := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+ *               := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+ln2 =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+huge=  1.00000000000000000000e+300;
+
+double
+asinh(double x)
+{
+        double t,w;
+        int32_t hx,ix;
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7ff00000) return x+x;  /* x is inf or NaN */
+        if(ix< 0x3e300000) {    /* |x|<2**-28 */
+            if(huge+x>one) return x;    /* return x inexact except 0 */
+        }
+        if(ix>0x41b00000) {     /* |x| > 2**28 */
+            w = log(fabs(x))+ln2;
+        } else if (ix>0x40000000) {     /* 2**28 > |x| > 2.0 */
+            t = fabs(x);
+            w = log(2.0*t+one/(sqrt(x*x+one)+t));
+        } else {                /* 2.0 > |x| > 2**-28 */
+            t = x*x;
+            w =log1p(fabs(x)+t/(one+sqrt(one+t)));
+        }
+        if(hx>0) return w; else return -w;
+}
diff --git a/src/math/s_asinhf.c b/src/math/s_asinhf.c
new file mode 100644
index 00000000..04f8d072
--- /dev/null
+++ b/src/math/s_asinhf.c
@@ -0,0 +1,45 @@
+/* s_asinhf.c -- float version of s_asinh.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 <math.h>
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3F800000 */
+ln2 =  6.9314718246e-01, /* 0x3f317218 */
+huge=  1.0000000000e+30;
+
+float
+asinhf(float x)
+{
+        float t,w;
+        int32_t hx,ix;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7f800000) return x+x;  /* x is inf or NaN */
+        if(ix< 0x31800000) {    /* |x|<2**-28 */
+            if(huge+x>one) return x;    /* return x inexact except 0 */
+        }
+        if(ix>0x4d800000) {     /* |x| > 2**28 */
+            w = logf(fabsf(x))+ln2;
+        } else if (ix>0x40000000) {     /* 2**28 > |x| > 2.0 */
+            t = fabsf(x);
+            w = logf((float)2.0*t+one/(sqrtf(x*x+one)+t));
+        } else {                /* 2.0 > |x| > 2**-28 */
+            t = x*x;
+            w =log1pf(fabsf(x)+t/(one+sqrtf(one+t)));
+        }
+        if(hx>0) return w; else return -w;
+}
diff --git a/src/math/s_atan.c b/src/math/s_atan.c
new file mode 100644
index 00000000..1faac024
--- /dev/null
+++ b/src/math/s_atan.c
@@ -0,0 +1,115 @@
+/* @(#)s_atan.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* atan(x)
+ * Method
+ *   1. Reduce x to positive by atan(x) = -atan(-x).
+ *   2. According to the integer k=4t+0.25 chopped, t=x, the argument
+ *      is further reduced to one of the following intervals and the
+ *      arctangent of t is evaluated by the corresponding formula:
+ *
+ *      [0,7/16]      atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
+ *      [7/16,11/16]  atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
+ *      [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
+ *      [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
+ *      [39/16,INF]   atan(x) = atan(INF) + atan( -1/t )
+ *
+ * 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 <math.h>
+#include "math_private.h"
+
+static const double atanhi[] = {
+  4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
+  7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
+  9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
+  1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
+};
+
+static const double atanlo[] = {
+  2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
+  3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
+  1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
+  6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
+};
+
+static const double aT[] = {
+  3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
+ -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
+  1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
+ -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
+  9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
+ -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
+  6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
+ -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
+  4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
+ -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
+  1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
+};
+
+        static const double
+one   = 1.0,
+huge   = 1.0e300;
+
+double
+atan(double x)
+{
+        double w,s1,s2,z;
+        int32_t ix,hx,id;
+
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x44100000) {    /* if |x| >= 2^66 */
+            uint32_t low;
+            GET_LOW_WORD(low,x);
+            if(ix>0x7ff00000||
+                (ix==0x7ff00000&&(low!=0)))
+                return x+x;             /* NaN */
+            if(hx>0) return  atanhi[3]+atanlo[3];
+            else     return -atanhi[3]-atanlo[3];
+        } if (ix < 0x3fdc0000) {        /* |x| < 0.4375 */
+            if (ix < 0x3e200000) {      /* |x| < 2^-29 */
+                if(huge+x>one) return x;        /* raise inexact */
+            }
+            id = -1;
+        } else {
+        x = fabs(x);
+        if (ix < 0x3ff30000) {          /* |x| < 1.1875 */
+            if (ix < 0x3fe60000) {      /* 7/16 <=|x|<11/16 */
+                id = 0; x = (2.0*x-one)/(2.0+x);
+            } else {                    /* 11/16<=|x|< 19/16 */
+                id = 1; x  = (x-one)/(x+one);
+            }
+        } else {
+            if (ix < 0x40038000) {      /* |x| < 2.4375 */
+                id = 2; x  = (x-1.5)/(one+1.5*x);
+            } else {                    /* 2.4375 <= |x| < 2^66 */
+                id = 3; x  = -1.0/x;
+            }
+        }}
+    /* end of argument reduction */
+        z = x*x;
+        w = z*z;
+    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+        s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+        s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+        if (id<0) return x - x*(s1+s2);
+        else {
+            z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+            return (hx<0)? -z:z;
+        }
+}
diff --git a/src/math/s_atanf.c b/src/math/s_atanf.c
new file mode 100644
index 00000000..03067e18
--- /dev/null
+++ b/src/math/s_atanf.c
@@ -0,0 +1,95 @@
+/* s_atanf.c -- float version of s_atan.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 <math.h>
+#include "math_private.h"
+
+static const float atanhi[] = {
+  4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
+  7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
+  9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
+  1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
+};
+
+static const float atanlo[] = {
+  5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
+  3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
+  3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
+  7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
+};
+
+static const float aT[] = {
+  3.3333334327e-01, /* 0x3eaaaaaa */
+ -2.0000000298e-01, /* 0xbe4ccccd */
+  1.4285714924e-01, /* 0x3e124925 */
+ -1.1111110449e-01, /* 0xbde38e38 */
+  9.0908870101e-02, /* 0x3dba2e6e */
+ -7.6918758452e-02, /* 0xbd9d8795 */
+  6.6610731184e-02, /* 0x3d886b35 */
+ -5.8335702866e-02, /* 0xbd6ef16b */
+  4.9768779427e-02, /* 0x3d4bda59 */
+ -3.6531571299e-02, /* 0xbd15a221 */
+  1.6285819933e-02, /* 0x3c8569d7 */
+};
+
+        static const float
+one   = 1.0,
+huge   = 1.0e30;
+
+float
+atanf(float x)
+{
+        float w,s1,s2,z;
+        int32_t ix,hx,id;
+
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x50800000) {    /* if |x| >= 2^34 */
+            if(ix>0x7f800000)
+                return x+x;             /* NaN */
+            if(hx>0) return  atanhi[3]+atanlo[3];
+            else     return -atanhi[3]-atanlo[3];
+        } if (ix < 0x3ee00000) {        /* |x| < 0.4375 */
+            if (ix < 0x31000000) {      /* |x| < 2^-29 */
+                if(huge+x>one) return x;        /* raise inexact */
+            }
+            id = -1;
+        } else {
+        x = fabsf(x);
+        if (ix < 0x3f980000) {          /* |x| < 1.1875 */
+            if (ix < 0x3f300000) {      /* 7/16 <=|x|<11/16 */
+                id = 0; x = ((float)2.0*x-one)/((float)2.0+x);
+            } else {                    /* 11/16<=|x|< 19/16 */
+                id = 1; x  = (x-one)/(x+one);
+            }
+        } else {
+            if (ix < 0x401c0000) {      /* |x| < 2.4375 */
+                id = 2; x  = (x-(float)1.5)/(one+(float)1.5*x);
+            } else {                    /* 2.4375 <= |x| < 2^66 */
+                id = 3; x  = -(float)1.0/x;
+            }
+        }}
+    /* end of argument reduction */
+        z = x*x;
+        w = z*z;
+    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+        s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+        s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+        if (id<0) return x - x*(s1+s2);
+        else {
+            z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+            return (hx<0)? -z:z;
+        }
+}
diff --git a/src/math/s_cbrt.c b/src/math/s_cbrt.c
new file mode 100644
index 00000000..8adcb191
--- /dev/null
+++ b/src/math/s_cbrt.c
@@ -0,0 +1,77 @@
+/* @(#)s_cbrt.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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 <math.h>
+#include "math_private.h"
+
+/* cbrt(x)
+ * Return cube root of x
+ */
+static const uint32_t
+        B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */
+        B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
+
+static const double
+C =  5.42857142857142815906e-01, /* 19/35     = 0x3FE15F15, 0xF15F15F1 */
+D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */
+E =  1.41428571428571436819e+00, /* 99/70     = 0x3FF6A0EA, 0x0EA0EA0F */
+F =  1.60714285714285720630e+00, /* 45/28     = 0x3FF9B6DB, 0x6DB6DB6E */
+G =  3.57142857142857150787e-01; /* 5/14      = 0x3FD6DB6D, 0xB6DB6DB7 */
+
+double
+cbrt(double x)
+{
+        int32_t hx;
+        double r,s,t=0.0,w;
+        uint32_t sign;
+        uint32_t high,low;
+
+        GET_HIGH_WORD(hx,x);
+        sign=hx&0x80000000;             /* sign= sign(x) */
+        hx  ^=sign;
+        if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
+        GET_LOW_WORD(low,x);
+        if((hx|low)==0)
+            return(x);          /* cbrt(0) is itself */
+
+        SET_HIGH_WORD(x,hx);    /* x <- |x| */
+    /* rough cbrt to 5 bits */
+        if(hx<0x00100000)               /* subnormal number */
+          {SET_HIGH_WORD(t,0x43500000); /* set t= 2**54 */
+           t*=x; GET_HIGH_WORD(high,t); SET_HIGH_WORD(t,high/3+B2);
+          }
+        else
+          SET_HIGH_WORD(t,hx/3+B1);
+
+
+    /* new cbrt to 23 bits, may be implemented in single precision */
+        r=t*t/x;
+        s=C+r*t;
+        t*=G+F/(s+E+D/s);
+
+    /* chopped to 20 bits and make it larger than cbrt(x) */
+        GET_HIGH_WORD(high,t);
+        INSERT_WORDS(t,high+0x00000001,0);
+
+
+    /* one step newton iteration to 53 bits with error less than 0.667 ulps */
+        s=t*t;          /* t*t is exact */
+        r=x/s;
+        w=t+t;
+        r=(r-t)/(w+r);  /* r-s is exact */
+        t=t+t*r;
+
+    /* retore the sign bit */
+        GET_HIGH_WORD(high,t);
+        SET_HIGH_WORD(t,high|sign);
+        return(t);
+}
diff --git a/src/math/s_cbrtf.c b/src/math/s_cbrtf.c
new file mode 100644
index 00000000..e7b46de7
--- /dev/null
+++ b/src/math/s_cbrtf.c
@@ -0,0 +1,67 @@
+/* s_cbrtf.c -- float version of s_cbrt.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 <math.h>
+#include "math_private.h"
+
+/* cbrtf(x)
+ * Return cube root of x
+ */
+static const unsigned
+        B1 = 709958130, /* B1 = (84+2/3-0.03306235651)*2**23 */
+        B2 = 642849266; /* B2 = (76+2/3-0.03306235651)*2**23 */
+
+static const float
+C =  5.4285717010e-01, /* 19/35     = 0x3f0af8b0 */
+D = -7.0530611277e-01, /* -864/1225 = 0xbf348ef1 */
+E =  1.4142856598e+00, /* 99/70     = 0x3fb50750 */
+F =  1.6071428061e+00, /* 45/28     = 0x3fcdb6db */
+G =  3.5714286566e-01; /* 5/14      = 0x3eb6db6e */
+
+float
+cbrtf(float x)
+{
+        float r,s,t;
+        int32_t hx;
+        uint32_t sign;
+        uint32_t high;
+
+        GET_FLOAT_WORD(hx,x);
+        sign=hx&0x80000000;             /* sign= sign(x) */
+        hx  ^=sign;
+        if(hx>=0x7f800000) return(x+x); /* cbrt(NaN,INF) is itself */
+        if(hx==0)
+            return(x);          /* cbrt(0) is itself */
+
+        SET_FLOAT_WORD(x,hx);   /* x <- |x| */
+    /* rough cbrt to 5 bits */
+        if(hx<0x00800000)               /* subnormal number */
+          {SET_FLOAT_WORD(t,0x4b800000); /* set t= 2**24 */
+           t*=x; GET_FLOAT_WORD(high,t); SET_FLOAT_WORD(t,high/3+B2);
+          }
+        else
+          SET_FLOAT_WORD(t,hx/3+B1);
+
+
+    /* new cbrt to 23 bits */
+        r=t*t/x;
+        s=C+r*t;
+        t*=G+F/(s+E+D/s);
+
+    /* retore the sign bit */
+        GET_FLOAT_WORD(high,t);
+        SET_FLOAT_WORD(t,high|sign);
+        return(t);
+}
diff --git a/src/math/s_ceil.c b/src/math/s_ceil.c
new file mode 100644
index 00000000..1670cade
--- /dev/null
+++ b/src/math/s_ceil.c
@@ -0,0 +1,68 @@
+/* @(#)s_ceil.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *      Bit twiddling.
+ * Exception:
+ *      Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+double
+ceil(double x)
+{
+        int32_t i0,i1,j0;
+        uint32_t i,j;
+        EXTRACT_WORDS(i0,i1,x);
+        j0 = ((i0>>20)&0x7ff)-0x3ff;
+        if(j0<20) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+                    if(i0<0) {i0=0x80000000;i1=0;}
+                    else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
+                }
+            } else {
+                i = (0x000fffff)>>j0;
+                if(((i0&i)|i1)==0) return x; /* x is integral */
+                if(huge+x>0.0) {        /* raise inexact flag */
+                    if(i0>0) i0 += (0x00100000)>>j0;
+                    i0 &= (~i); i1=0;
+                }
+            }
+        } else if (j0>51) {
+            if(j0==0x400) return x+x;   /* inf or NaN */
+            else return x;              /* x is integral */
+        } else {
+            i = ((uint32_t)(0xffffffff))>>(j0-20);
+            if((i1&i)==0) return x;     /* x is integral */
+            if(huge+x>0.0) {            /* raise inexact flag */
+                if(i0>0) {
+                    if(j0==20) i0+=1;
+                    else {
+                        j = i1 + (1<<(52-j0));
+                        if(j<i1) i0+=1; /* got a carry */
+                        i1 = j;
+                    }
+                }
+                i1 &= (~i);
+            }
+        }
+        INSERT_WORDS(x,i0,i1);
+        return x;
+}
diff --git a/src/math/s_ceilf.c b/src/math/s_ceilf.c
new file mode 100644
index 00000000..3615041f
--- /dev/null
+++ b/src/math/s_ceilf.c
@@ -0,0 +1,49 @@
+/* s_ceilf.c -- float version of s_ceil.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 <math.h>
+#include "math_private.h"
+
+static const float huge = 1.0e30;
+
+float
+ceilf(float x)
+{
+        int32_t i0,j0;
+        uint32_t i;
+
+        GET_FLOAT_WORD(i0,x);
+        j0 = ((i0>>23)&0xff)-0x7f;
+        if(j0<23) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
+                    if(i0<0) {i0=0x80000000;}
+                    else if(i0!=0) { i0=0x3f800000;}
+                }
+            } else {
+                i = (0x007fffff)>>j0;
+                if((i0&i)==0) return x; /* x is integral */
+                if(huge+x>(float)0.0) { /* raise inexact flag */
+                    if(i0>0) i0 += (0x00800000)>>j0;
+                    i0 &= (~i);
+                }
+            }
+        } else {
+            if(j0==0x80) return x+x;    /* inf or NaN */
+            else return x;              /* x is integral */
+        }
+        SET_FLOAT_WORD(x,i0);
+        return x;
+}
diff --git a/src/math/s_copysign.c b/src/math/s_copysign.c
new file mode 100644
index 00000000..59d3877c
--- /dev/null
+++ b/src/math/s_copysign.c
@@ -0,0 +1,30 @@
+/* @(#)s_copysign.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * copysign(double x, double y)
+ * copysign(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+copysign(double x, double y)
+{
+        uint32_t hx,hy;
+        GET_HIGH_WORD(hx,x);
+        GET_HIGH_WORD(hy,y);
+        SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000));
+        return x;
+}
diff --git a/src/math/s_copysignf.c b/src/math/s_copysignf.c
new file mode 100644
index 00000000..d650e8e5
--- /dev/null
+++ b/src/math/s_copysignf.c
@@ -0,0 +1,33 @@
+/* s_copysignf.c -- float version of s_copysign.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.
+ * ====================================================
+ */
+
+/*
+ * copysignf(float x, float y)
+ * copysignf(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+float
+copysignf(float x, float y)
+{
+        uint32_t ix,iy;
+        GET_FLOAT_WORD(ix,x);
+        GET_FLOAT_WORD(iy,y);
+        SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000));
+        return x;
+}
diff --git a/src/math/s_cos.c b/src/math/s_cos.c
new file mode 100644
index 00000000..1893ab13
--- /dev/null
+++ b/src/math/s_cos.c
@@ -0,0 +1,74 @@
+/* @(#)s_cos.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* cos(x)
+ * Return cosine function of x.
+ *
+ * kernel function:
+ *      __kernel_sin            ... sine function on [-pi/4,pi/4]
+ *      __kernel_cos            ... cosine function on [-pi/4,pi/4]
+ *      __ieee754_rem_pio2      ... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on
+ *      [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ *      in [-pi/4 , +pi/4], and let n = k mod 4.
+ *      We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *          0          S           C             T
+ *          1          C          -S            -1/T
+ *          2         -S          -C             T
+ *          3         -C           S            -1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *      TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+cos(double x)
+{
+        double y[2],z=0.0;
+        int32_t n, ix;
+
+    /* High word of x. */
+        GET_HIGH_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3fe921fb) return __kernel_cos(x,z);
+
+    /* cos(Inf or NaN) is NaN */
+        else if (ix>=0x7ff00000) return x-x;
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2(x,y);
+            switch(n&3) {
+                case 0: return  __kernel_cos(y[0],y[1]);
+                case 1: return -__kernel_sin(y[0],y[1],1);
+                case 2: return -__kernel_cos(y[0],y[1]);
+                default:
+                        return  __kernel_sin(y[0],y[1],1);
+            }
+        }
+}
diff --git a/src/math/s_cosf.c b/src/math/s_cosf.c
new file mode 100644
index 00000000..14b8e98b
--- /dev/null
+++ b/src/math/s_cosf.c
@@ -0,0 +1,47 @@
+/* s_cosf.c -- float version of s_cos.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 <math.h>
+#include "math_private.h"
+
+static const float one=1.0;
+
+float
+cosf(float x)
+{
+        float y[2],z=0.0;
+        int32_t n,ix;
+
+        GET_FLOAT_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3f490fd8) return __kernel_cosf(x,z);
+
+    /* cos(Inf or NaN) is NaN */
+        else if (ix>=0x7f800000) return x-x;
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2f(x,y);
+            switch(n&3) {
+                case 0: return  __kernel_cosf(y[0],y[1]);
+                case 1: return -__kernel_sinf(y[0],y[1],1);
+                case 2: return -__kernel_cosf(y[0],y[1]);
+                default:
+                        return  __kernel_sinf(y[0],y[1],1);
+            }
+        }
+}
diff --git a/src/math/s_erf.c b/src/math/s_erf.c
new file mode 100644
index 00000000..e321feea
--- /dev/null
+++ b/src/math/s_erf.c
@@ -0,0 +1,298 @@
+/* @(#)s_erf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* double erf(double x)
+ * double erfc(double x)
+ *                           x
+ *                    2      |\
+ *     erf(x)  =  ---------  | exp(-t*t)dt
+ *                 sqrt(pi) \|
+ *                           0
+ *
+ *     erfc(x) =  1-erf(x)
+ *  Note that
+ *              erf(-x) = -erf(x)
+ *              erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ *      1. For |x| in [0, 0.84375]
+ *          erf(x)  = x + x*R(x^2)
+ *          erfc(x) = 1 - erf(x)           if x in [-.84375,0.25]
+ *                  = 0.5 + ((0.5-x)-x*R)  if x in [0.25,0.84375]
+ *         where R = P/Q where P is an odd poly of degree 8 and
+ *         Q is an odd poly of degree 10.
+ *                                               -57.90
+ *                      | R - (erf(x)-x)/x | <= 2
+ *
+ *
+ *         Remark. The formula is derived by noting
+ *          erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ *         and that
+ *          2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ *         is close to one. The interval is chosen because the fix
+ *         point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+ *         near 0.6174), and by some experiment, 0.84375 is chosen to
+ *         guarantee the error is less than one ulp for erf.
+ *
+ *      2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+ *         c = 0.84506291151 rounded to single (24 bits)
+ *              erf(x)  = sign(x) * (c  + P1(s)/Q1(s))
+ *              erfc(x) = (1-c)  - P1(s)/Q1(s) if x > 0
+ *                        1+(c+P1(s)/Q1(s))    if x < 0
+ *              |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+ *         Remark: here we use the taylor series expansion at x=1.
+ *              erf(1+s) = erf(1) + s*Poly(s)
+ *                       = 0.845.. + P1(s)/Q1(s)
+ *         That is, we use rational approximation to approximate
+ *                      erf(1+s) - (c = (single)0.84506291151)
+ *         Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ *         where
+ *              P1(s) = degree 6 poly in s
+ *              Q1(s) = degree 6 poly in s
+ *
+ *      3. For x in [1.25,1/0.35(~2.857143)],
+ *              erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+ *              erf(x)  = 1 - erfc(x)
+ *         where
+ *              R1(z) = degree 7 poly in z, (z=1/x^2)
+ *              S1(z) = degree 8 poly in z
+ *
+ *      4. For x in [1/0.35,28]
+ *              erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+ *                      = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+ *                      = 2.0 - tiny            (if x <= -6)
+ *              erf(x)  = sign(x)*(1.0 - erfc(x)) if x < 6, else
+ *              erf(x)  = sign(x)*(1.0 - tiny)
+ *         where
+ *              R2(z) = degree 6 poly in z, (z=1/x^2)
+ *              S2(z) = degree 7 poly in z
+ *
+ *      Note1:
+ *         To compute exp(-x*x-0.5625+R/S), let s be a single
+ *         precision number and s := x; then
+ *              -x*x = -s*s + (s-x)*(s+x)
+ *              exp(-x*x-0.5626+R/S) =
+ *                      exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ *      Note2:
+ *         Here 4 and 5 make use of the asymptotic series
+ *                        exp(-x*x)
+ *              erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ *                        x*sqrt(pi)
+ *         We use rational approximation to approximate
+ *              g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
+ *         Here is the error bound for R1/S1 and R2/S2
+ *              |R1/S1 - f(x)|  < 2**(-62.57)
+ *              |R2/S2 - f(x)|  < 2**(-61.52)
+ *
+ *      5. For inf > x >= 28
+ *              erf(x)  = sign(x) *(1 - tiny)  (raise inexact)
+ *              erfc(x) = tiny*tiny (raise underflow) if x > 0
+ *                      = 2 - tiny if x<0
+ *
+ *      7. Special case:
+ *              erf(0)  = 0, erf(inf)  = 1, erf(-inf) = -1,
+ *              erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+ *              erfc/erf(NaN) is NaN
+ */
+
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+tiny        = 1e-300,
+half=  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+two =  2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+        /* c = (float)0.84506291151 */
+erx =  8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
+/*
+ * Coefficients for approximation to  erf on [0,0.84375]
+ */
+efx =  1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */
+efx8=  1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
+pp0  =  1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
+pp1  = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
+pp2  = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
+pp3  = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
+pp4  = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
+qq1  =  3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
+qq2  =  6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
+qq3  =  5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
+qq4  =  1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
+qq5  = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
+/*
+ * Coefficients for approximation to  erf  in [0.84375,1.25]
+ */
+pa0  = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
+pa1  =  4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
+pa2  = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
+pa3  =  3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
+pa4  = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
+pa5  =  3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
+pa6  = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
+qa1  =  1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
+qa2  =  5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
+qa3  =  7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
+qa4  =  1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
+qa5  =  1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
+qa6  =  1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
+/*
+ * Coefficients for approximation to  erfc in [1.25,1/0.35]
+ */
+ra0  = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
+ra1  = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
+ra2  = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
+ra3  = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
+ra4  = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
+ra5  = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
+ra6  = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
+ra7  = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
+sa1  =  1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
+sa2  =  1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
+sa3  =  4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
+sa4  =  6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
+sa5  =  4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
+sa6  =  1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
+sa7  =  6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
+sa8  = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
+/*
+ * Coefficients for approximation to  erfc in [1/.35,28]
+ */
+rb0  = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
+rb1  = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
+rb2  = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
+rb3  = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
+rb4  = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
+rb5  = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
+rb6  = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
+sb1  =  3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
+sb2  =  3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
+sb3  =  1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
+sb4  =  3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
+sb5  =  2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
+sb6  =  4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
+sb7  = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
+
+double
+erf(double x)
+{
+        int32_t hx,ix,i;
+        double R,S,P,Q,s,y,z,r;
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7ff00000) {            /* erf(nan)=nan */
+            i = ((uint32_t)hx>>31)<<1;
+            return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */
+        }
+
+        if(ix < 0x3feb0000) {           /* |x|<0.84375 */
+            if(ix < 0x3e300000) {       /* |x|<2**-28 */
+                if (ix < 0x00800000)
+                    return 0.125*(8.0*x+efx8*x);  /*avoid underflow */
+                return x + efx*x;
+            }
+            z = x*x;
+            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+            y = r/s;
+            return x + x*y;
+        }
+        if(ix < 0x3ff40000) {           /* 0.84375 <= |x| < 1.25 */
+            s = fabs(x)-one;
+            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+            if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+        }
+        if (ix >= 0x40180000) {         /* inf>|x|>=6 */
+            if(hx>=0) return one-tiny; else return tiny-one;
+        }
+        x = fabs(x);
+        s = one/(x*x);
+        if(ix< 0x4006DB6E) {    /* |x| < 1/0.35 */
+            R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+                                ra5+s*(ra6+s*ra7))))));
+            S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+                                sa5+s*(sa6+s*(sa7+s*sa8)))))));
+        } else {        /* |x| >= 1/0.35 */
+            R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+                                rb5+s*rb6)))));
+            S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+                                sb5+s*(sb6+s*sb7))))));
+        }
+        z  = x;
+        SET_LOW_WORD(z,0);
+        r  =  exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S);
+        if(hx>=0) return one-r/x; else return  r/x-one;
+}
+
+double
+erfc(double x)
+{
+        int32_t hx,ix;
+        double R,S,P,Q,s,y,z,r;
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7ff00000) {                    /* erfc(nan)=nan */
+                                                /* erfc(+-inf)=0,2 */
+            return (double)(((uint32_t)hx>>31)<<1)+one/x;
+        }
+
+        if(ix < 0x3feb0000) {           /* |x|<0.84375 */
+            if(ix < 0x3c700000)         /* |x|<2**-56 */
+                return one-x;
+            z = x*x;
+            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+            y = r/s;
+            if(hx < 0x3fd00000) {       /* x<1/4 */
+                return one-(x+x*y);
+            } else {
+                r = x*y;
+                r += (x-half);
+                return half - r ;
+            }
+        }
+        if(ix < 0x3ff40000) {           /* 0.84375 <= |x| < 1.25 */
+            s = fabs(x)-one;
+            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+            if(hx>=0) {
+                z  = one-erx; return z - P/Q;
+            } else {
+                z = erx+P/Q; return one+z;
+            }
+        }
+        if (ix < 0x403c0000) {          /* |x|<28 */
+            x = fabs(x);
+            s = one/(x*x);
+            if(ix< 0x4006DB6D) {        /* |x| < 1/.35 ~ 2.857143*/
+                R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+                                ra5+s*(ra6+s*ra7))))));
+                S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+                                sa5+s*(sa6+s*(sa7+s*sa8)))))));
+            } else {                    /* |x| >= 1/.35 ~ 2.857143 */
+                if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */
+                R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+                                rb5+s*rb6)))));
+                S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+                                sb5+s*(sb6+s*sb7))))));
+            }
+            z  = x;
+            SET_LOW_WORD(z,0);
+            r  =  exp(-z*z-0.5625)*
+                        exp((z-x)*(z+x)+R/S);
+            if(hx>0) return r/x; else return two-r/x;
+        } else {
+            if(hx>0) return tiny*tiny; else return two-tiny;
+        }
+}
diff --git a/src/math/s_erff.c b/src/math/s_erff.c
new file mode 100644
index 00000000..28e2f7b3
--- /dev/null
+++ b/src/math/s_erff.c
@@ -0,0 +1,207 @@
+/* s_erff.c -- float version of s_erf.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 <math.h>
+#include "math_private.h"
+
+static const float
+tiny        = 1e-30,
+half=  5.0000000000e-01, /* 0x3F000000 */
+one =  1.0000000000e+00, /* 0x3F800000 */
+two =  2.0000000000e+00, /* 0x40000000 */
+        /* c = (subfloat)0.84506291151 */
+erx =  8.4506291151e-01, /* 0x3f58560b */
+/*
+ * Coefficients for approximation to  erf on [0,0.84375]
+ */
+efx =  1.2837916613e-01, /* 0x3e0375d4 */
+efx8=  1.0270333290e+00, /* 0x3f8375d4 */
+pp0  =  1.2837916613e-01, /* 0x3e0375d4 */
+pp1  = -3.2504209876e-01, /* 0xbea66beb */
+pp2  = -2.8481749818e-02, /* 0xbce9528f */
+pp3  = -5.7702702470e-03, /* 0xbbbd1489 */
+pp4  = -2.3763017452e-05, /* 0xb7c756b1 */
+qq1  =  3.9791721106e-01, /* 0x3ecbbbce */
+qq2  =  6.5022252500e-02, /* 0x3d852a63 */
+qq3  =  5.0813062117e-03, /* 0x3ba68116 */
+qq4  =  1.3249473704e-04, /* 0x390aee49 */
+qq5  = -3.9602282413e-06, /* 0xb684e21a */
+/*
+ * Coefficients for approximation to  erf  in [0.84375,1.25]
+ */
+pa0  = -2.3621185683e-03, /* 0xbb1acdc6 */
+pa1  =  4.1485610604e-01, /* 0x3ed46805 */
+pa2  = -3.7220788002e-01, /* 0xbebe9208 */
+pa3  =  3.1834661961e-01, /* 0x3ea2fe54 */
+pa4  = -1.1089469492e-01, /* 0xbde31cc2 */
+pa5  =  3.5478305072e-02, /* 0x3d1151b3 */
+pa6  = -2.1663755178e-03, /* 0xbb0df9c0 */
+qa1  =  1.0642088205e-01, /* 0x3dd9f331 */
+qa2  =  5.4039794207e-01, /* 0x3f0a5785 */
+qa3  =  7.1828655899e-02, /* 0x3d931ae7 */
+qa4  =  1.2617121637e-01, /* 0x3e013307 */
+qa5  =  1.3637083583e-02, /* 0x3c5f6e13 */
+qa6  =  1.1984500103e-02, /* 0x3c445aa3 */
+/*
+ * Coefficients for approximation to  erfc in [1.25,1/0.35]
+ */
+ra0  = -9.8649440333e-03, /* 0xbc21a093 */
+ra1  = -6.9385856390e-01, /* 0xbf31a0b7 */
+ra2  = -1.0558626175e+01, /* 0xc128f022 */
+ra3  = -6.2375331879e+01, /* 0xc2798057 */
+ra4  = -1.6239666748e+02, /* 0xc322658c */
+ra5  = -1.8460508728e+02, /* 0xc3389ae7 */
+ra6  = -8.1287437439e+01, /* 0xc2a2932b */
+ra7  = -9.8143291473e+00, /* 0xc11d077e */
+sa1  =  1.9651271820e+01, /* 0x419d35ce */
+sa2  =  1.3765776062e+02, /* 0x4309a863 */
+sa3  =  4.3456588745e+02, /* 0x43d9486f */
+sa4  =  6.4538726807e+02, /* 0x442158c9 */
+sa5  =  4.2900814819e+02, /* 0x43d6810b */
+sa6  =  1.0863500214e+02, /* 0x42d9451f */
+sa7  =  6.5702495575e+00, /* 0x40d23f7c */
+sa8  = -6.0424413532e-02, /* 0xbd777f97 */
+/*
+ * Coefficients for approximation to  erfc in [1/.35,28]
+ */
+rb0  = -9.8649431020e-03, /* 0xbc21a092 */
+rb1  = -7.9928326607e-01, /* 0xbf4c9dd4 */
+rb2  = -1.7757955551e+01, /* 0xc18e104b */
+rb3  = -1.6063638306e+02, /* 0xc320a2ea */
+rb4  = -6.3756646729e+02, /* 0xc41f6441 */
+rb5  = -1.0250950928e+03, /* 0xc480230b */
+rb6  = -4.8351919556e+02, /* 0xc3f1c275 */
+sb1  =  3.0338060379e+01, /* 0x41f2b459 */
+sb2  =  3.2579251099e+02, /* 0x43a2e571 */
+sb3  =  1.5367296143e+03, /* 0x44c01759 */
+sb4  =  3.1998581543e+03, /* 0x4547fdbb */
+sb5  =  2.5530502930e+03, /* 0x451f90ce */
+sb6  =  4.7452853394e+02, /* 0x43ed43a7 */
+sb7  = -2.2440952301e+01; /* 0xc1b38712 */
+
+float
+erff(float x)
+{
+        int32_t hx,ix,i;
+        float R,S,P,Q,s,y,z,r;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7f800000) {            /* erf(nan)=nan */
+            i = ((uint32_t)hx>>31)<<1;
+            return (float)(1-i)+one/x;  /* erf(+-inf)=+-1 */
+        }
+
+        if(ix < 0x3f580000) {           /* |x|<0.84375 */
+            if(ix < 0x31800000) {       /* |x|<2**-28 */
+                if (ix < 0x04000000)
+                    /*avoid underflow */
+                    return (float)0.125*((float)8.0*x+efx8*x);
+                return x + efx*x;
+            }
+            z = x*x;
+            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+            y = r/s;
+            return x + x*y;
+        }
+        if(ix < 0x3fa00000) {           /* 0.84375 <= |x| < 1.25 */
+            s = fabsf(x)-one;
+            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+            if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+        }
+        if (ix >= 0x40c00000) {         /* inf>|x|>=6 */
+            if(hx>=0) return one-tiny; else return tiny-one;
+        }
+        x = fabsf(x);
+        s = one/(x*x);
+        if(ix< 0x4036DB6E) {    /* |x| < 1/0.35 */
+            R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+                                ra5+s*(ra6+s*ra7))))));
+            S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+                                sa5+s*(sa6+s*(sa7+s*sa8)))))));
+        } else {        /* |x| >= 1/0.35 */
+            R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+                                rb5+s*rb6)))));
+            S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+                                sb5+s*(sb6+s*sb7))))));
+        }
+        GET_FLOAT_WORD(ix,x);
+        SET_FLOAT_WORD(z,ix&0xfffff000);
+        r  =  expf(-z*z-(float)0.5625)*expf((z-x)*(z+x)+R/S);
+        if(hx>=0) return one-r/x; else return  r/x-one;
+}
+
+float
+erfcf(float x)
+{
+        int32_t hx,ix;
+        float R,S,P,Q,s,y,z,r;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7f800000) {                    /* erfc(nan)=nan */
+                                                /* erfc(+-inf)=0,2 */
+            return (float)(((uint32_t)hx>>31)<<1)+one/x;
+        }
+
+        if(ix < 0x3f580000) {           /* |x|<0.84375 */
+            if(ix < 0x23800000)         /* |x|<2**-56 */
+                return one-x;
+            z = x*x;
+            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+            y = r/s;
+            if(hx < 0x3e800000) {       /* x<1/4 */
+                return one-(x+x*y);
+            } else {
+                r = x*y;
+                r += (x-half);
+                return half - r ;
+            }
+        }
+        if(ix < 0x3fa00000) {           /* 0.84375 <= |x| < 1.25 */
+            s = fabsf(x)-one;
+            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+            if(hx>=0) {
+                z  = one-erx; return z - P/Q;
+            } else {
+                z = erx+P/Q; return one+z;
+            }
+        }
+        if (ix < 0x41e00000) {          /* |x|<28 */
+            x = fabsf(x);
+            s = one/(x*x);
+            if(ix< 0x4036DB6D) {        /* |x| < 1/.35 ~ 2.857143*/
+                R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+                                ra5+s*(ra6+s*ra7))))));
+                S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+                                sa5+s*(sa6+s*(sa7+s*sa8)))))));
+            } else {                    /* |x| >= 1/.35 ~ 2.857143 */
+                if(hx<0&&ix>=0x40c00000) return two-tiny;/* x < -6 */
+                R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+                                rb5+s*rb6)))));
+                S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+                                sb5+s*(sb6+s*sb7))))));
+            }
+            GET_FLOAT_WORD(ix,x);
+            SET_FLOAT_WORD(z,ix&0xfffff000);
+            r  =  expf(-z*z-(float)0.5625)*
+                        expf((z-x)*(z+x)+R/S);
+            if(hx>0) return r/x; else return two-r/x;
+        } else {
+            if(hx>0) return tiny*tiny; else return two-tiny;
+        }
+}
diff --git a/src/math/s_expm1.c b/src/math/s_expm1.c
new file mode 100644
index 00000000..6f1f6675
--- /dev/null
+++ b/src/math/s_expm1.c
@@ -0,0 +1,217 @@
+/* @(#)s_expm1.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* expm1(x)
+ * Returns exp(x)-1, the exponential of x minus 1.
+ *
+ * Method
+ *   1. Argument reduction:
+ *      Given x, find r and integer k such that
+ *
+ *               x = k*ln2 + r,  |r| <= 0.5*ln2 ~ 0.34658
+ *
+ *      Here a correction term c will be computed to compensate
+ *      the error in r when rounded to a floating-point number.
+ *
+ *   2. Approximating expm1(r) by a special rational function on
+ *      the interval [0,0.34658]:
+ *      Since
+ *          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
+ *      we define R1(r*r) by
+ *          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
+ *      That is,
+ *          R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+ *                   = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+ *                   = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
+ *      We use a special Reme algorithm on [0,0.347] to generate
+ *      a polynomial of degree 5 in r*r to approximate R1. The
+ *      maximum error of this polynomial approximation is bounded
+ *      by 2**-61. In other words,
+ *          R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+ *      where   Q1  =  -1.6666666666666567384E-2,
+ *              Q2  =   3.9682539681370365873E-4,
+ *              Q3  =  -9.9206344733435987357E-6,
+ *              Q4  =   2.5051361420808517002E-7,
+ *              Q5  =  -6.2843505682382617102E-9;
+ *      (where z=r*r, and the values of Q1 to Q5 are listed below)
+ *      with error bounded by
+ *          |                  5           |     -61
+ *          | 1.0+Q1*z+...+Q5*z   -  R1(z) | <= 2
+ *          |                              |
+ *
+ *      expm1(r) = exp(r)-1 is then computed by the following
+ *      specific way which minimize the accumulation rounding error:
+ *                             2     3
+ *                            r     r    [ 3 - (R1 + R1*r/2)  ]
+ *            expm1(r) = r + --- + --- * [--------------------]
+ *                            2     2    [ 6 - r*(3 - R1*r/2) ]
+ *
+ *      To compensate the error in the argument reduction, we use
+ *              expm1(r+c) = expm1(r) + c + expm1(r)*c
+ *                         ~ expm1(r) + c + r*c
+ *      Thus c+r*c will be added in as the correction terms for
+ *      expm1(r+c). Now rearrange the term to avoid optimization
+ *      screw up:
+ *                      (      2                                    2 )
+ *                      ({  ( r    [ R1 -  (3 - R1*r/2) ]  )  }    r  )
+ *       expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+ *                      ({  ( 2    [ 6 - r*(3 - R1*r/2) ]  )  }    2  )
+ *                      (                                             )
+ *
+ *                 = r - E
+ *   3. Scale back to obtain expm1(x):
+ *      From step 1, we have
+ *         expm1(x) = either 2^k*[expm1(r)+1] - 1
+ *                  = or     2^k*[expm1(r) + (1-2^-k)]
+ *   4. Implementation notes:
+ *      (A). To save one multiplication, we scale the coefficient Qi
+ *           to Qi*2^i, and replace z by (x^2)/2.
+ *      (B). To achieve maximum accuracy, we compute expm1(x) by
+ *        (i)   if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+ *        (ii)  if k=0, return r-E
+ *        (iii) if k=-1, return 0.5*(r-E)-0.5
+ *        (iv)  if k=1 if r < -0.25, return 2*((r+0.5)- E)
+ *                     else          return  1.0+2.0*(r-E);
+ *        (v)   if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
+ *        (vi)  if k <= 20, return 2^k((1-2^-k)-(E-r)), else
+ *        (vii) return 2^k(1-((E+2^-k)-r))
+ *
+ * Special cases:
+ *      expm1(INF) is INF, expm1(NaN) is NaN;
+ *      expm1(-INF) is -1, and
+ *      for finite argument, only expm1(0)=0 is exact.
+ *
+ * Accuracy:
+ *      according to an error analysis, the error is always less than
+ *      1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ *      For IEEE double
+ *          if x >  7.09782712893383973096e+02 then expm1(x) overflow
+ *
+ * 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 <math.h>
+#include "math_private.h"
+
+static const double
+one             = 1.0,
+huge            = 1.0e+300,
+tiny            = 1.0e-300,
+o_threshold     = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */
+ln2_hi          = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */
+ln2_lo          = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */
+invln2          = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */
+        /* scaled coefficients related to expm1 */
+Q1  =  -3.33333333333331316428e-02, /* BFA11111 111110F4 */
+Q2  =   1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
+Q3  =  -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
+Q4  =   4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
+Q5  =  -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
+
+double
+expm1(double x)
+{
+        double y,hi,lo,c=0.0,t,e,hxs,hfx,r1;
+        int32_t k,xsb;
+        uint32_t hx;
+
+        GET_HIGH_WORD(hx,x);
+        xsb = hx&0x80000000;            /* sign bit of x */
+        if(xsb==0) y=x; else y= -x;     /* y = |x| */
+        hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out huge and non-finite argument */
+        if(hx >= 0x4043687A) {                  /* if |x|>=56*ln2 */
+            if(hx >= 0x40862E42) {              /* if |x|>=709.78... */
+                if(hx>=0x7ff00000) {
+                    uint32_t low;
+                    GET_LOW_WORD(low,x);
+                    if(((hx&0xfffff)|low)!=0)
+                         return x+x;     /* NaN */
+                    else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+                }
+                if(x > o_threshold) return huge*huge; /* overflow */
+            }
+            if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */
+                if(x+tiny<0.0)          /* raise inexact */
+                return tiny-one;        /* return -1 */
+            }
+        }
+
+    /* argument reduction */
+        if(hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */
+            if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+                if(xsb==0)
+                    {hi = x - ln2_hi; lo =  ln2_lo;  k =  1;}
+                else
+                    {hi = x + ln2_hi; lo = -ln2_lo;  k = -1;}
+            } else {
+                k  = invln2*x+((xsb==0)?0.5:-0.5);
+                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 < 0x3c900000) {      /* when |x|<2**-54, return x */
+            t = huge+x; /* return x with inexact flags when x!=0 */
+            return x - (t-(huge+x));
+        }
+        else k = 0;
+
+    /* x is now in primary range */
+        hfx = 0.5*x;
+        hxs = x*hfx;
+        r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+        t  = 3.0-r1*hfx;
+        e  = hxs*((r1-t)/(6.0 - x*t));
+        if(k==0) return x - (x*e-hxs);          /* c is 0 */
+        else {
+            e  = (x*(e-c)-c);
+            e -= hxs;
+            if(k== -1) return 0.5*(x-e)-0.5;
+            if(k==1) {
+                if(x < -0.25) return -2.0*(e-(x+0.5));
+                else          return  one+2.0*(x-e);
+            }
+            if (k <= -2 || k>56) {   /* suffice to return exp(x)-1 */
+                uint32_t high;
+                y = one-(e-x);
+                GET_HIGH_WORD(high,y);
+                SET_HIGH_WORD(y,high+(k<<20));  /* add k to y's exponent */
+                return y-one;
+            }
+            t = one;
+            if(k<20) {
+                uint32_t high;
+                SET_HIGH_WORD(t,0x3ff00000 - (0x200000>>k));  /* t=1-2^-k */
+                y = t-(e-x);
+                GET_HIGH_WORD(high,y);
+                SET_HIGH_WORD(y,high+(k<<20));  /* add k to y's exponent */
+           } else {
+                uint32_t high;
+                SET_HIGH_WORD(t,((0x3ff-k)<<20));       /* 2^-k */
+                y = x-(e+t);
+                y += one;
+                GET_HIGH_WORD(high,y);
+                SET_HIGH_WORD(y,high+(k<<20));  /* add k to y's exponent */
+            }
+        }
+        return y;
+}
diff --git a/src/math/s_expm1f.c b/src/math/s_expm1f.c
new file mode 100644
index 00000000..b22cf0f9
--- /dev/null
+++ b/src/math/s_expm1f.c
@@ -0,0 +1,122 @@
+/* s_expm1f.c -- float version of s_expm1.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 <math.h>
+#include "math_private.h"
+
+static const float
+one             = 1.0,
+huge            = 1.0e+30,
+tiny            = 1.0e-30,
+o_threshold     = 8.8721679688e+01,/* 0x42b17180 */
+ln2_hi          = 6.9313812256e-01,/* 0x3f317180 */
+ln2_lo          = 9.0580006145e-06,/* 0x3717f7d1 */
+invln2          = 1.4426950216e+00,/* 0x3fb8aa3b */
+        /* scaled coefficients related to expm1 */
+Q1  =  -3.3333335072e-02, /* 0xbd088889 */
+Q2  =   1.5873016091e-03, /* 0x3ad00d01 */
+Q3  =  -7.9365076090e-05, /* 0xb8a670cd */
+Q4  =   4.0082177293e-06, /* 0x36867e54 */
+Q5  =  -2.0109921195e-07; /* 0xb457edbb */
+
+float
+expm1f(float x)
+{
+        float y,hi,lo,c=0.0,t,e,hxs,hfx,r1;
+        int32_t k,xsb;
+        uint32_t hx;
+
+        GET_FLOAT_WORD(hx,x);
+        xsb = hx&0x80000000;            /* sign bit of x */
+        if(xsb==0) y=x; else y= -x;     /* y = |x| */
+        hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out huge and non-finite argument */
+        if(hx >= 0x4195b844) {                  /* if |x|>=27*ln2 */
+            if(hx >= 0x42b17218) {              /* if |x|>=88.721... */
+                if(hx>0x7f800000)
+                    return x+x;          /* NaN */
+                if(hx==0x7f800000)
+                    return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+                if(x > o_threshold) return huge*huge; /* overflow */
+            }
+            if(xsb!=0) { /* x < -27*ln2, return -1.0 with inexact */
+                if(x+tiny<(float)0.0)   /* raise inexact */
+                return tiny-one;        /* return -1 */
+            }
+        }
+
+    /* argument reduction */
+        if(hx > 0x3eb17218) {           /* if  |x| > 0.5 ln2 */
+            if(hx < 0x3F851592) {       /* and |x| < 1.5 ln2 */
+                if(xsb==0)
+                    {hi = x - ln2_hi; lo =  ln2_lo;  k =  1;}
+                else
+                    {hi = x + ln2_hi; lo = -ln2_lo;  k = -1;}
+            } else {
+                k  = invln2*x+((xsb==0)?(float)0.5:(float)-0.5);
+                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 */
+            t = huge+x; /* return x with inexact flags when x!=0 */
+            return x - (t-(huge+x));
+        }
+        else k = 0;
+
+    /* x is now in primary range */
+        hfx = (float)0.5*x;
+        hxs = x*hfx;
+        r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+        t  = (float)3.0-r1*hfx;
+        e  = hxs*((r1-t)/((float)6.0 - x*t));
+        if(k==0) return x - (x*e-hxs);          /* c is 0 */
+        else {
+            e  = (x*(e-c)-c);
+            e -= hxs;
+            if(k== -1) return (float)0.5*(x-e)-(float)0.5;
+            if(k==1) {
+                if(x < (float)-0.25) return -(float)2.0*(e-(x+(float)0.5));
+                else          return  one+(float)2.0*(x-e);
+            }
+            if (k <= -2 || k>56) {   /* suffice to return exp(x)-1 */
+                int32_t i;
+                y = one-(e-x);
+                GET_FLOAT_WORD(i,y);
+                SET_FLOAT_WORD(y,i+(k<<23));    /* add k to y's exponent */
+                return y-one;
+            }
+            t = one;
+            if(k<23) {
+                int32_t i;
+                SET_FLOAT_WORD(t,0x3f800000 - (0x1000000>>k)); /* t=1-2^-k */
+                y = t-(e-x);
+                GET_FLOAT_WORD(i,y);
+                SET_FLOAT_WORD(y,i+(k<<23));    /* add k to y's exponent */
+           } else {
+                int32_t i;
+                SET_FLOAT_WORD(t,((0x7f-k)<<23));       /* 2^-k */
+                y = x-(e+t);
+                y += one;
+                GET_FLOAT_WORD(i,y);
+                SET_FLOAT_WORD(y,i+(k<<23));    /* add k to y's exponent */
+            }
+        }
+        return y;
+}
diff --git a/src/math/s_fabs.c b/src/math/s_fabs.c
new file mode 100644
index 00000000..74433250
--- /dev/null
+++ b/src/math/s_fabs.c
@@ -0,0 +1,27 @@
+/* @(#)s_fabs.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+fabs(double x)
+{
+        uint32_t high;
+        GET_HIGH_WORD(high,x);
+        SET_HIGH_WORD(x,high&0x7fffffff);
+        return x;
+}
diff --git a/src/math/s_fabsf.c b/src/math/s_fabsf.c
new file mode 100644
index 00000000..655d57d8
--- /dev/null
+++ b/src/math/s_fabsf.c
@@ -0,0 +1,30 @@
+/* s_fabsf.c -- float version of s_fabs.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.
+ * ====================================================
+ */
+
+/*
+ * fabsf(x) returns the absolute value of x.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+float
+fabsf(float x)
+{
+        uint32_t ix;
+        GET_FLOAT_WORD(ix,x);
+        SET_FLOAT_WORD(x,ix&0x7fffffff);
+        return x;
+}
diff --git a/src/math/s_floor.c b/src/math/s_floor.c
new file mode 100644
index 00000000..273cf6f4
--- /dev/null
+++ b/src/math/s_floor.c
@@ -0,0 +1,69 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * floor(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *      Bit twiddling.
+ * Exception:
+ *      Inexact flag raised if x not equal to floor(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+double
+floor(double x)
+{
+        int32_t i0,i1,j0;
+        uint32_t i,j;
+        EXTRACT_WORDS(i0,i1,x);
+        j0 = ((i0>>20)&0x7ff)-0x3ff;
+        if(j0<20) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+                    if(i0>=0) {i0=i1=0;}
+                    else if(((i0&0x7fffffff)|i1)!=0)
+                        { i0=0xbff00000;i1=0;}
+                }
+            } else {
+                i = (0x000fffff)>>j0;
+                if(((i0&i)|i1)==0) return x; /* x is integral */
+                if(huge+x>0.0) {        /* raise inexact flag */
+                    if(i0<0) i0 += (0x00100000)>>j0;
+                    i0 &= (~i); i1=0;
+                }
+            }
+        } else if (j0>51) {
+            if(j0==0x400) return x+x;   /* inf or NaN */
+            else return x;              /* x is integral */
+        } else {
+            i = ((uint32_t)(0xffffffff))>>(j0-20);
+            if((i1&i)==0) return x;     /* x is integral */
+            if(huge+x>0.0) {            /* raise inexact flag */
+                if(i0<0) {
+                    if(j0==20) i0+=1;
+                    else {
+                        j = i1+(1<<(52-j0));
+                        if(j<i1) i0 +=1 ;       /* got a carry */
+                        i1=j;
+                    }
+                }
+                i1 &= (~i);
+            }
+        }
+        INSERT_WORDS(x,i0,i1);
+        return x;
+}
diff --git a/src/math/s_floorf.c b/src/math/s_floorf.c
new file mode 100644
index 00000000..1164decc
--- /dev/null
+++ b/src/math/s_floorf.c
@@ -0,0 +1,58 @@
+/* s_floorf.c -- float version of s_floor.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.
+ * ====================================================
+ */
+
+/*
+ * floorf(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *      Bit twiddling.
+ * Exception:
+ *      Inexact flag raised if x not equal to floorf(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float huge = 1.0e30;
+
+float
+floorf(float x)
+{
+        int32_t i0,j0;
+        uint32_t i;
+        GET_FLOAT_WORD(i0,x);
+        j0 = ((i0>>23)&0xff)-0x7f;
+        if(j0<23) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
+                    if(i0>=0) {i0=0;}
+                    else if((i0&0x7fffffff)!=0)
+                        { i0=0xbf800000;}
+                }
+            } else {
+                i = (0x007fffff)>>j0;
+                if((i0&i)==0) return x; /* x is integral */
+                if(huge+x>(float)0.0) { /* raise inexact flag */
+                    if(i0<0) i0 += (0x00800000)>>j0;
+                    i0 &= (~i);
+                }
+            }
+        } else {
+            if(j0==0x80) return x+x;    /* inf or NaN */
+            else return x;              /* x is integral */
+        }
+        SET_FLOAT_WORD(x,i0);
+        return x;
+}
diff --git a/src/math/s_ilogb.c b/src/math/s_ilogb.c
new file mode 100644
index 00000000..f1ac498a
--- /dev/null
+++ b/src/math/s_ilogb.c
@@ -0,0 +1,45 @@
+/* @(#)s_ilogb.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* ilogb(double x)
+ * return the binary exponent of non-zero x
+ * ilogb(0) = FP_ILOGB0
+ * ilogb(NaN) = FP_ILOGBNAN (no signal is raised)
+ * ilogb(inf) = INT_MAX (no signal is raised)
+ */
+
+#include <limits.h>
+
+#include <math.h>
+#include "math_private.h"
+
+int ilogb(double x)
+{
+        int32_t hx,lx,ix;
+
+        EXTRACT_WORDS(hx,lx,x);
+        hx &= 0x7fffffff;
+        if(hx<0x00100000) {
+            if((hx|lx)==0)
+                return FP_ILOGB0;
+            else                        /* subnormal x */
+                if(hx==0) {
+                    for (ix = -1043; lx>0; lx<<=1) ix -=1;
+                } else {
+                    for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1;
+                }
+            return ix;
+        }
+        else if (hx<0x7ff00000) return (hx>>20)-1023;
+        else if (hx>0x7ff00000 || lx!=0) return FP_ILOGBNAN;
+        else return INT_MAX;
+}
diff --git a/src/math/s_ilogbf.c b/src/math/s_ilogbf.c
new file mode 100644
index 00000000..30359fef
--- /dev/null
+++ b/src/math/s_ilogbf.c
@@ -0,0 +1,37 @@
+/* s_ilogbf.c -- float version of s_ilogb.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 <limits.h>
+
+#include <math.h>
+#include "math_private.h"
+
+int ilogbf(float x)
+{
+        int32_t hx,ix;
+
+        GET_FLOAT_WORD(hx,x);
+        hx &= 0x7fffffff;
+        if(hx<0x00800000) {
+            if(hx==0)
+                return FP_ILOGB0;
+            else                        /* subnormal x */
+                for (ix = -126,hx<<=8; hx>0; hx<<=1) ix -=1;
+            return ix;
+        }
+        else if (hx<0x7f800000) return (hx>>23)-127;
+        else if (hx>0x7f800000) return FP_ILOGBNAN;
+        else return INT_MAX;
+}
diff --git a/src/math/s_ldexp.c b/src/math/s_ldexp.c
new file mode 100644
index 00000000..f4d1cd6a
--- /dev/null
+++ b/src/math/s_ldexp.c
@@ -0,0 +1,6 @@
+#include <math.h>
+
+double ldexp(double x, int n)
+{
+	return scalbn(x, n);
+}
diff --git a/src/math/s_ldexpf.c b/src/math/s_ldexpf.c
new file mode 100644
index 00000000..3bad5f39
--- /dev/null
+++ b/src/math/s_ldexpf.c
@@ -0,0 +1,6 @@
+#include <math.h>
+
+float ldexpf(float x, int n)
+{
+	return scalbnf(x, n);
+}
diff --git a/src/math/s_llrint.c b/src/math/s_llrint.c
new file mode 100644
index 00000000..2b1e00d0
--- /dev/null
+++ b/src/math/s_llrint.c
@@ -0,0 +1,8 @@
+#include <math.h>
+
+// FIXME: incorrect exception behavior
+
+long long llrint(double x)
+{
+	return rint(x);
+}
diff --git a/src/math/s_log1p.c b/src/math/s_log1p.c
new file mode 100644
index 00000000..886d5ab1
--- /dev/null
+++ b/src/math/s_log1p.c
@@ -0,0 +1,157 @@
+/* @(#)s_log1p.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* double log1p(double x)
+ *
+ * Method :
+ *   1. Argument Reduction: find k and f such that
+ *                      1+x = 2^k * (1+f),
+ *         where  sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ *      Note. If k=0, then f=x is exact. However, if k!=0, then f
+ *      may not be representable exactly. In that case, a correction
+ *      term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+ *      log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+ *      and add back the correction term c/u.
+ *      (Note: when x > 2**53, one can simply return log(x))
+ *
+ *   2. Approximation of log1p(f).
+ *      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ *               = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ *               = 2s + s*R
+ *      We use a special Reme algorithm on [0,0.1716] to generate
+ *      a polynomial of degree 14 to approximate R The maximum error
+ *      of this polynomial approximation is bounded by 2**-58.45. In
+ *      other words,
+ *                      2      4      6      8      10      12      14
+ *          R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s
+ *      (the values of Lp1 to Lp7 are listed in the program)
+ *      and
+ *          |      2          14          |     -58.45
+ *          | Lp1*s +...+Lp7*s    -  R(z) | <= 2
+ *          |                             |
+ *      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ *      In order to guarantee error in log below 1ulp, we compute log
+ *      by
+ *              log1p(f) = f - (hfsq - s*(hfsq+R)).
+ *
+ *      3. Finally, log1p(x) = k*ln2 + log1p(f).
+ *                           = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ *         Here ln2 is split into two floating point number:
+ *                      ln2_hi + ln2_lo,
+ *         where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ *      log1p(x) is NaN with signal if x < -1 (including -INF) ;
+ *      log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+ *      log1p(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ *      according to an error analysis, the error is always less than
+ *      1 ulp (unit in the last place).
+ *
+ * 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.
+ *
+ * Note: Assuming log() return accurate answer, the following
+ *       algorithm can be used to compute log1p(x) to within a few ULP:
+ *
+ *              u = 1+x;
+ *              if(u==1.0) return x ; else
+ *                         return log(u)*(x/(u-1.0));
+ *
+ *       See HP-15C Advanced Functions Handbook, p.193.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+ln2_hi  =  6.93147180369123816490e-01,  /* 3fe62e42 fee00000 */
+ln2_lo  =  1.90821492927058770002e-10,  /* 3dea39ef 35793c76 */
+two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */
+Lp1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lp2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lp3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lp4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lp5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lp6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lp7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
+
+static const double zero = 0.0;
+
+double
+log1p(double x)
+{
+        double hfsq,f=0,c=0,s,z,R,u;
+        int32_t k,hx,hu=0,ax;
+
+        GET_HIGH_WORD(hx,x);
+        ax = hx&0x7fffffff;
+
+        k = 1;
+        if (hx < 0x3FDA827A) {                  /* x < 0.41422  */
+            if(ax>=0x3ff00000) {                /* x <= -1.0 */
+                if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */
+                else return (x-x)/(x-x);        /* log1p(x<-1)=NaN */
+            }
+            if(ax<0x3e200000) {                 /* |x| < 2**-29 */
+                if(two54+x>zero                 /* raise inexact */
+                    &&ax<0x3c900000)            /* |x| < 2**-54 */
+                    return x;
+                else
+                    return x - x*x*0.5;
+            }
+            if(hx>0||hx<=((int32_t)0xbfd2bec3)) {
+                k=0;f=x;hu=1;}  /* -0.2929<x<0.41422 */
+        }
+        if (hx >= 0x7ff00000) return x+x;
+        if(k!=0) {
+            if(hx<0x43400000) {
+                u  = 1.0+x;
+                GET_HIGH_WORD(hu,u);
+                k  = (hu>>20)-1023;
+                c  = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */
+                c /= u;
+            } else {
+                u  = x;
+                GET_HIGH_WORD(hu,u);
+                k  = (hu>>20)-1023;
+                c  = 0;
+            }
+            hu &= 0x000fffff;
+            if(hu<0x6a09e) {
+                SET_HIGH_WORD(u,hu|0x3ff00000); /* normalize u */
+            } else {
+                k += 1;
+                SET_HIGH_WORD(u,hu|0x3fe00000); /* normalize u/2 */
+                hu = (0x00100000-hu)>>2;
+            }
+            f = u-1.0;
+        }
+        hfsq=0.5*f*f;
+        if(hu==0) {     /* |f| < 2**-20 */
+            if(f==zero) { if(k==0) return zero;
+                          else {c += k*ln2_lo; return k*ln2_hi+c;} }
+            R = hfsq*(1.0-0.66666666666666666*f);
+            if(k==0) return f-R; else
+                     return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+        }
+        s = f/(2.0+f);
+        z = s*s;
+        R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+        if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                 return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/src/math/s_log1pf.c b/src/math/s_log1pf.c
new file mode 100644
index 00000000..dcdd6bb3
--- /dev/null
+++ b/src/math/s_log1pf.c
@@ -0,0 +1,96 @@
+/* s_log1pf.c -- float version of s_log1p.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 <math.h>
+#include "math_private.h"
+
+static const float
+ln2_hi =   6.9313812256e-01,    /* 0x3f317180 */
+ln2_lo =   9.0580006145e-06,    /* 0x3717f7d1 */
+two25 =    3.355443200e+07,     /* 0x4c000000 */
+Lp1 = 6.6666668653e-01, /* 3F2AAAAB */
+Lp2 = 4.0000000596e-01, /* 3ECCCCCD */
+Lp3 = 2.8571429849e-01, /* 3E924925 */
+Lp4 = 2.2222198546e-01, /* 3E638E29 */
+Lp5 = 1.8183572590e-01, /* 3E3A3325 */
+Lp6 = 1.5313838422e-01, /* 3E1CD04F */
+Lp7 = 1.4798198640e-01; /* 3E178897 */
+
+static const float zero = 0.0;
+
+float
+log1pf(float x)
+{
+        float hfsq,f=0,c=0,s,z,R,u;
+        int32_t k,hx,hu=0,ax;
+
+        GET_FLOAT_WORD(hx,x);
+        ax = hx&0x7fffffff;
+
+        k = 1;
+        if (hx < 0x3ed413d7) {                  /* x < 0.41422  */
+            if(ax>=0x3f800000) {                /* x <= -1.0 */
+                if(x==(float)-1.0) return -two25/zero; /* log1p(-1)=+inf */
+                else return (x-x)/(x-x);        /* log1p(x<-1)=NaN */
+            }
+            if(ax<0x31000000) {                 /* |x| < 2**-29 */
+                if(two25+x>zero                 /* raise inexact */
+                    &&ax<0x24800000)            /* |x| < 2**-54 */
+                    return x;
+                else
+                    return x - x*x*(float)0.5;
+            }
+            if(hx>0||hx<=((int32_t)0xbe95f61f)) {
+                k=0;f=x;hu=1;}  /* -0.2929<x<0.41422 */
+        }
+        if (hx >= 0x7f800000) return x+x;
+        if(k!=0) {
+            if(hx<0x5a000000) {
+                u  = (float)1.0+x;
+                GET_FLOAT_WORD(hu,u);
+                k  = (hu>>23)-127;
+                /* correction term */
+                c  = (k>0)? (float)1.0-(u-x):x-(u-(float)1.0);
+                c /= u;
+            } else {
+                u  = x;
+                GET_FLOAT_WORD(hu,u);
+                k  = (hu>>23)-127;
+                c  = 0;
+            }
+            hu &= 0x007fffff;
+            if(hu<0x3504f7) {
+                SET_FLOAT_WORD(u,hu|0x3f800000);/* normalize u */
+            } else {
+                k += 1;
+                SET_FLOAT_WORD(u,hu|0x3f000000);        /* normalize u/2 */
+                hu = (0x00800000-hu)>>2;
+            }
+            f = u-(float)1.0;
+        }
+        hfsq=(float)0.5*f*f;
+        if(hu==0) {     /* |f| < 2**-20 */
+            if(f==zero) { if(k==0) return zero;
+                          else {c += k*ln2_lo; return k*ln2_hi+c;} }
+            R = hfsq*((float)1.0-(float)0.66666666666666666*f);
+            if(k==0) return f-R; else
+                     return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+        }
+        s = f/((float)2.0+f);
+        z = s*s;
+        R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+        if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                 return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/src/math/s_logb.c b/src/math/s_logb.c
new file mode 100644
index 00000000..be399c77
--- /dev/null
+++ b/src/math/s_logb.c
@@ -0,0 +1,34 @@
+/* @(#)s_logb.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * double logb(x)
+ * IEEE 754 logb. Included to pass IEEE test suite. Not recommend.
+ * Use ilogb instead.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+logb(double x)
+{
+        int32_t lx,ix;
+        EXTRACT_WORDS(ix,lx,x);
+        ix &= 0x7fffffff;                       /* high |x| */
+        if((ix|lx)==0) return -1.0/fabs(x);
+        if(ix>=0x7ff00000) return x*x;
+        if((ix>>=20)==0)                        /* IEEE 754 logb */
+                return -1022.0;
+        else
+                return (double) (ix-1023);
+}
diff --git a/src/math/s_logbf.c b/src/math/s_logbf.c
new file mode 100644
index 00000000..747664d3
--- /dev/null
+++ b/src/math/s_logbf.c
@@ -0,0 +1,31 @@
+/* s_logbf.c -- float version of s_logb.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 <math.h>
+#include "math_private.h"
+
+float
+logbf(float x)
+{
+        int32_t ix;
+        GET_FLOAT_WORD(ix,x);
+        ix &= 0x7fffffff;                       /* high |x| */
+        if(ix==0) return (float)-1.0/fabsf(x);
+        if(ix>=0x7f800000) return x*x;
+        if((ix>>=23)==0)                        /* IEEE 754 logb */
+                return -126.0;
+        else
+                return (float) (ix-127);
+}
diff --git a/src/math/s_lrint.c b/src/math/s_lrint.c
new file mode 100644
index 00000000..da8e1989
--- /dev/null
+++ b/src/math/s_lrint.c
@@ -0,0 +1,8 @@
+#include <math.h>
+
+// FIXME: incorrect exception behavior
+
+long lrint(double x)
+{
+	return rint(x);
+}
diff --git a/src/math/s_lrintf.c b/src/math/s_lrintf.c
new file mode 100644
index 00000000..d0b469b9
--- /dev/null
+++ b/src/math/s_lrintf.c
@@ -0,0 +1,8 @@
+#include <math.h>
+
+// FIXME: incorrect exception behavior
+
+long lrintf(float x)
+{
+	return rintf(x);
+}
diff --git a/src/math/s_modf.c b/src/math/s_modf.c
new file mode 100644
index 00000000..a5528d6b
--- /dev/null
+++ b/src/math/s_modf.c
@@ -0,0 +1,71 @@
+/* @(#)s_modf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * modf(double x, double *iptr)
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ *      Bit twiddling.
+ *
+ * Exception:
+ *      No exception.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one = 1.0;
+
+double
+modf(double x, double *iptr)
+{
+        int32_t i0,i1,j0;
+        uint32_t i;
+        EXTRACT_WORDS(i0,i1,x);
+        j0 = ((i0>>20)&0x7ff)-0x3ff;    /* exponent of x */
+        if(j0<20) {                     /* integer part in high x */
+            if(j0<0) {                  /* |x|<1 */
+                INSERT_WORDS(*iptr,i0&0x80000000,0);    /* *iptr = +-0 */
+                return x;
+            } else {
+                i = (0x000fffff)>>j0;
+                if(((i0&i)|i1)==0) {            /* x is integral */
+                    uint32_t high;
+                    *iptr = x;
+                    GET_HIGH_WORD(high,x);
+                    INSERT_WORDS(x,high&0x80000000,0);  /* return +-0 */
+                    return x;
+                } else {
+                    INSERT_WORDS(*iptr,i0&(~i),0);
+                    return x - *iptr;
+                }
+            }
+        } else if (j0>51) {             /* no fraction part */
+            uint32_t high;
+            *iptr = x*one;
+            GET_HIGH_WORD(high,x);
+            INSERT_WORDS(x,high&0x80000000,0);  /* return +-0 */
+            return x;
+        } else {                        /* fraction part in low x */
+            i = ((uint32_t)(0xffffffff))>>(j0-20);
+            if((i1&i)==0) {             /* x is integral */
+                uint32_t high;
+                *iptr = x;
+                GET_HIGH_WORD(high,x);
+                INSERT_WORDS(x,high&0x80000000,0);      /* return +-0 */
+                return x;
+            } else {
+                INSERT_WORDS(*iptr,i0,i1&(~i));
+                return x - *iptr;
+            }
+        }
+}
diff --git a/src/math/s_modff.c b/src/math/s_modff.c
new file mode 100644
index 00000000..de4dfd25
--- /dev/null
+++ b/src/math/s_modff.c
@@ -0,0 +1,52 @@
+/* s_modff.c -- float version of s_modf.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 <math.h>
+#include "math_private.h"
+
+static const float one = 1.0;
+
+float
+modff(float x, float *iptr)
+{
+        int32_t i0,j0;
+        uint32_t i;
+        GET_FLOAT_WORD(i0,x);
+        j0 = ((i0>>23)&0xff)-0x7f;      /* exponent of x */
+        if(j0<23) {                     /* integer part in x */
+            if(j0<0) {                  /* |x|<1 */
+                SET_FLOAT_WORD(*iptr,i0&0x80000000);    /* *iptr = +-0 */
+                return x;
+            } else {
+                i = (0x007fffff)>>j0;
+                if((i0&i)==0) {                 /* x is integral */
+                    uint32_t ix;
+                    *iptr = x;
+                    GET_FLOAT_WORD(ix,x);
+                    SET_FLOAT_WORD(x,ix&0x80000000);    /* return +-0 */
+                    return x;
+                } else {
+                    SET_FLOAT_WORD(*iptr,i0&(~i));
+                    return x - *iptr;
+                }
+            }
+        } else {                        /* no fraction part */
+            uint32_t ix;
+            *iptr = x*one;
+            GET_FLOAT_WORD(ix,x);
+            SET_FLOAT_WORD(x,ix&0x80000000);    /* return +-0 */
+            return x;
+        }
+}
diff --git a/src/math/s_nextafter.c b/src/math/s_nextafter.c
new file mode 100644
index 00000000..46d298ec
--- /dev/null
+++ b/src/math/s_nextafter.c
@@ -0,0 +1,72 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* IEEE functions
+ *      nextafter(x,y)
+ *      return the next machine floating-point number of x in the
+ *      direction toward y.
+ *   Special cases:
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+nextafter(double x, double y)
+{
+        volatile double t;
+        int32_t hx,hy,ix,iy;
+        uint32_t lx,ly;
+
+        EXTRACT_WORDS(hx,lx,x);
+        EXTRACT_WORDS(hy,ly,y);
+        ix = hx&0x7fffffff;             /* |x| */
+        iy = hy&0x7fffffff;             /* |y| */
+
+        if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
+           ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))     /* y is nan */
+           return x+y;
+        if(x==y) return y;              /* x=y, return y */
+        if((ix|lx)==0) {                        /* x == 0 */
+            INSERT_WORDS(x,hy&0x80000000,1);    /* return +-minsubnormal */
+            t = x*x;
+            if(t==x) return t; else return x;   /* raise underflow flag */
+        }
+        if(hx>=0) {                             /* x > 0 */
+            if(hx>hy||((hx==hy)&&(lx>ly))) {    /* x > y, x -= ulp */
+                if(lx==0) hx -= 1;
+                lx -= 1;
+            } else {                            /* x < y, x += ulp */
+                lx += 1;
+                if(lx==0) hx += 1;
+            }
+        } else {                                /* x < 0 */
+            if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
+                if(lx==0) hx -= 1;
+                lx -= 1;
+            } else {                            /* x > y, x += ulp */
+                lx += 1;
+                if(lx==0) hx += 1;
+            }
+        }
+        hy = hx&0x7ff00000;
+        if(hy>=0x7ff00000) return x+x;  /* overflow  */
+        if(hy<0x00100000) {             /* underflow */
+            t = x*x;
+            if(t!=x) {          /* raise underflow flag */
+                INSERT_WORDS(y,hx,lx);
+                return y;
+            }
+        }
+        INSERT_WORDS(x,hx,lx);
+        return x;
+}
diff --git a/src/math/s_nextafterf.c b/src/math/s_nextafterf.c
new file mode 100644
index 00000000..7ce08838
--- /dev/null
+++ b/src/math/s_nextafterf.c
@@ -0,0 +1,63 @@
+/* s_nextafterf.c -- float version of s_nextafter.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 <math.h>
+#include "math_private.h"
+
+float
+nextafterf(float x, float y)
+{
+        volatile float t;
+        int32_t hx,hy,ix,iy;
+
+        GET_FLOAT_WORD(hx,x);
+        GET_FLOAT_WORD(hy,y);
+        ix = hx&0x7fffffff;             /* |x| */
+        iy = hy&0x7fffffff;             /* |y| */
+
+        if((ix>0x7f800000) ||   /* x is nan */
+           (iy>0x7f800000))     /* y is nan */
+           return x+y;
+        if(x==y) return y;              /* x=y, return y */
+        if(ix==0) {                             /* x == 0 */
+            SET_FLOAT_WORD(x,(hy&0x80000000)|1);/* return +-minsubnormal */
+            t = x*x;
+            if(t==x) return t; else return x;   /* raise underflow flag */
+        }
+        if(hx>=0) {                             /* x > 0 */
+            if(hx>hy) {                         /* x > y, x -= ulp */
+                hx -= 1;
+            } else {                            /* x < y, x += ulp */
+                hx += 1;
+            }
+        } else {                                /* x < 0 */
+            if(hy>=0||hx>hy){                   /* x < y, x -= ulp */
+                hx -= 1;
+            } else {                            /* x > y, x += ulp */
+                hx += 1;
+            }
+        }
+        hy = hx&0x7f800000;
+        if(hy>=0x7f800000) return x+x;  /* overflow  */
+        if(hy<0x00800000) {             /* underflow */
+            t = x*x;
+            if(t!=x) {          /* raise underflow flag */
+                SET_FLOAT_WORD(y,hx);
+                return y;
+            }
+        }
+        SET_FLOAT_WORD(x,hx);
+        return x;
+}
diff --git a/src/math/s_remquo.c b/src/math/s_remquo.c
new file mode 100644
index 00000000..1a2992d6
--- /dev/null
+++ b/src/math/s_remquo.c
@@ -0,0 +1,149 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double Zero[] = {0.0, -0.0,};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer.  We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method.  In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ */
+double
+remquo(double x, double y, int *quo)
+{
+        int32_t n,hx,hy,hz,ix,iy,sx,i;
+        uint32_t lx,ly,lz,q,sxy;
+
+        EXTRACT_WORDS(hx,lx,x);
+        EXTRACT_WORDS(hy,ly,y);
+        sxy = (hx ^ hy) & 0x80000000;
+        sx = hx&0x80000000;             /* sign of x */
+        hx ^=sx;                /* |x| */
+        hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+        if((hy|ly)==0||(hx>=0x7ff00000)||       /* y=0,or x not finite */
+          ((hy|((ly|-ly)>>31))>0x7ff00000))     /* or y is NaN */
+            return (x*y)/(x*y);
+        if(hx<=hy) {
+            if((hx<hy)||(lx<ly)) {
+                q = 0;
+                goto fixup;     /* |x|<|y| return x or x-y */
+            }
+            if(lx==ly) {
+                *quo = 1;
+                return Zero[(uint32_t)sx>>31]; /* |x|=|y| return x*0*/
+            }
+        }
+
+    /* determine ix = ilogb(x) */
+        if(hx<0x00100000) {     /* subnormal x */
+            if(hx==0) {
+                for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+            } else {
+                for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+            }
+        } else ix = (hx>>20)-1023;
+
+    /* determine iy = ilogb(y) */
+        if(hy<0x00100000) {     /* subnormal y */
+            if(hy==0) {
+                for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+            } else {
+                for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+            }
+        } else iy = (hy>>20)-1023;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+        if(ix >= -1022) 
+            hx = 0x00100000|(0x000fffff&hx);
+        else {          /* subnormal x, shift x to normal */
+            n = -1022-ix;
+            if(n<=31) {
+                hx = (hx<<n)|(lx>>(32-n));
+                lx <<= n;
+            } else {
+                hx = lx<<(n-32);
+                lx = 0;
+            }
+        }
+        if(iy >= -1022) 
+            hy = 0x00100000|(0x000fffff&hy);
+        else {          /* subnormal y, shift y to normal */
+            n = -1022-iy;
+            if(n<=31) {
+                hy = (hy<<n)|(ly>>(32-n));
+                ly <<= n;
+            } else {
+                hy = ly<<(n-32);
+                ly = 0;
+            }
+        }
+
+    /* fix point fmod */
+        n = ix - iy;
+        q = 0;
+        while(n--) {
+            hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+            if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+            else {hx = hz+hz+(lz>>31); lx = lz+lz; q++;}
+            q <<= 1;
+        }
+        hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+        if(hz>=0) {hx=hz;lx=lz;q++;}
+
+    /* convert back to floating value and restore the sign */
+        if((hx|lx)==0) {                        /* return sign(x)*0 */
+            *quo = (sxy ? -q : q);
+            return Zero[(uint32_t)sx>>31];
+        }
+        while(hx<0x00100000) {          /* normalize x */
+            hx = hx+hx+(lx>>31); lx = lx+lx;
+            iy -= 1;
+        }
+        if(iy>= -1022) {        /* normalize output */
+            hx = ((hx-0x00100000)|((iy+1023)<<20));
+        } else {                /* subnormal output */
+            n = -1022 - iy;
+            if(n<=20) {
+                lx = (lx>>n)|((uint32_t)hx<<(32-n));
+                hx >>= n;
+            } else if (n<=31) {
+                lx = (hx<<(32-n))|(lx>>n); hx = sx;
+            } else {
+                lx = hx>>(n-32); hx = sx;
+            }
+        }
+fixup:
+        INSERT_WORDS(x,hx,lx);
+        y = fabs(y);
+        if (y < 0x1p-1021) {
+            if (x+x>y || (x+x==y && (q & 1))) {
+                q++;
+                x-=y;
+            }
+        } else if (x>0.5*y || (x==0.5*y && (q & 1))) {
+            q++;
+            x-=y;
+        }
+        GET_HIGH_WORD(hx,x);
+        SET_HIGH_WORD(x,hx^sx);
+        q &= 0x7fffffff;
+        *quo = (sxy ? -q : q);
+        return x;
+}
diff --git a/src/math/s_remquof.c b/src/math/s_remquof.c
new file mode 100644
index 00000000..be2a561a
--- /dev/null
+++ b/src/math/s_remquof.c
@@ -0,0 +1,118 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float Zero[] = {0.0, -0.0,};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer.  We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method.  In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ */
+float
+remquof(float x, float y, int *quo)
+{
+        int32_t n,hx,hy,hz,ix,iy,sx,i;
+        uint32_t q,sxy;
+
+        GET_FLOAT_WORD(hx,x);
+        GET_FLOAT_WORD(hy,y);
+        sxy = (hx ^ hy) & 0x80000000;
+        sx = hx&0x80000000;             /* sign of x */
+        hx ^=sx;                /* |x| */
+        hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+        if(hy==0||hx>=0x7f800000||hy>0x7f800000) /* y=0,NaN;or x not finite */
+            return (x*y)/(x*y);
+        if(hx<hy) {
+            q = 0;
+            goto fixup; /* |x|<|y| return x or x-y */
+        } else if(hx==hy) {
+            *quo = 1;
+            return Zero[(uint32_t)sx>>31];     /* |x|=|y| return x*0*/
+        }
+
+    /* determine ix = ilogb(x) */
+        if(hx<0x00800000) {     /* subnormal x */
+            for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1;
+        } else ix = (hx>>23)-127;
+
+    /* determine iy = ilogb(y) */
+        if(hy<0x00800000) {     /* subnormal y */
+            for (iy = -126,i=(hy<<8); i>0; i<<=1) iy -=1;
+        } else iy = (hy>>23)-127;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+        if(ix >= -126)
+            hx = 0x00800000|(0x007fffff&hx);
+        else {          /* subnormal x, shift x to normal */
+            n = -126-ix;
+            hx <<= n;
+        }
+        if(iy >= -126)
+            hy = 0x00800000|(0x007fffff&hy);
+        else {          /* subnormal y, shift y to normal */
+            n = -126-iy;
+            hy <<= n;
+        }
+
+    /* fix point fmod */
+        n = ix - iy;
+        q = 0;
+        while(n--) {
+            hz=hx-hy;
+            if(hz<0) hx = hx << 1;
+            else {hx = hz << 1; q++;}
+            q <<= 1;
+        }
+        hz=hx-hy;
+        if(hz>=0) {hx=hz;q++;}
+
+    /* convert back to floating value and restore the sign */
+        if(hx==0) {                             /* return sign(x)*0 */
+            *quo = (sxy ? -q : q);
+            return Zero[(uint32_t)sx>>31];
+        }
+        while(hx<0x00800000) {          /* normalize x */
+            hx <<= 1;
+            iy -= 1;
+        }
+        if(iy>= -126) {         /* normalize output */
+            hx = ((hx-0x00800000)|((iy+127)<<23));
+        } else {                /* subnormal output */
+            n = -126 - iy;
+            hx >>= n;
+        }
+fixup:
+        SET_FLOAT_WORD(x,hx);
+        y = fabsf(y);
+        if (y < 0x1p-125f) {
+            if (x+x>y || (x+x==y && (q & 1))) {
+                q++;
+                x-=y;
+            }
+        } else if (x>0.5f*y || (x==0.5f*y && (q & 1))) {
+            q++;
+            x-=y;
+        }
+        GET_FLOAT_WORD(hx,x);
+        SET_FLOAT_WORD(x,hx^sx);
+        q &= 0x7fffffff;
+        *quo = (sxy ? -q : q);
+        return x;
+}
diff --git a/src/math/s_rint.c b/src/math/s_rint.c
new file mode 100644
index 00000000..aec7d3c9
--- /dev/null
+++ b/src/math/s_rint.c
@@ -0,0 +1,80 @@
+/* @(#)s_rint.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * rint(x)
+ * Return x rounded to integral value according to the prevailing
+ * rounding mode.
+ * Method:
+ *      Using floating addition.
+ * Exception:
+ *      Inexact flag raised if x not equal to rint(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+/*
+ * TWO23 is long double instead of double to avoid a bug in gcc.  Without
+ * this, gcc thinks that TWO23[sx]+x and w-TWO23[sx] already have double
+ * precision and doesn't clip them to double precision when they are
+ * assigned and returned.
+ */
+static const long double
+TWO52[2]={
+  4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
+};
+
+double
+rint(double x)
+{
+        int32_t i0,j0,sx;
+        uint32_t i,i1;
+        double w,t;
+        EXTRACT_WORDS(i0,i1,x);
+        sx = (i0>>31)&1;
+        j0 = ((i0>>20)&0x7ff)-0x3ff;
+        if(j0<20) {
+            if(j0<0) {
+                if(((i0&0x7fffffff)|i1)==0) return x;
+                i1 |= (i0&0x0fffff);
+                i0 &= 0xfffe0000;
+                i0 |= ((i1|-i1)>>12)&0x80000;
+                SET_HIGH_WORD(x,i0);
+                w = TWO52[sx]+x;
+                t =  w-TWO52[sx];
+                GET_HIGH_WORD(i0,t);
+                SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31));
+                return t;
+            } else {
+                i = (0x000fffff)>>j0;
+                if(((i0&i)|i1)==0) return x; /* x is integral */
+                i>>=1;
+                if(((i0&i)|i1)!=0) {
+                    if(j0==19) i1 = 0x40000000; else
+                    i0 = (i0&(~i))|((0x20000)>>j0);
+                }
+            }
+        } else if (j0>51) {
+            if(j0==0x400) return x+x;   /* inf or NaN */
+            else return x;              /* x is integral */
+        } else {
+            i = ((uint32_t)(0xffffffff))>>(j0-20);
+            if((i1&i)==0) return x;     /* x is integral */
+            i>>=1;
+            if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
+        }
+        INSERT_WORDS(x,i0,i1);
+        w = TWO52[sx]+x;
+        return w-TWO52[sx];
+}
diff --git a/src/math/s_rintf.c b/src/math/s_rintf.c
new file mode 100644
index 00000000..c441870d
--- /dev/null
+++ b/src/math/s_rintf.c
@@ -0,0 +1,45 @@
+/* s_rintf.c -- float version of s_rint.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 <math.h>
+#include "math_private.h"
+
+static const float
+TWO23[2]={
+  8.3886080000e+06, /* 0x4b000000 */
+ -8.3886080000e+06, /* 0xcb000000 */
+};
+
+float
+rintf(float x)
+{
+        int32_t i0,j0,sx;
+        volatile float w,t;     /* volatile works around gcc bug */
+        GET_FLOAT_WORD(i0,x);
+        sx = (i0>>31)&1;
+        j0 = ((i0>>23)&0xff)-0x7f;
+        if(j0<23) {
+            if(j0<0) {
+                if((i0&0x7fffffff)==0) return x;
+                w = TWO23[sx]+x;
+                t =  w-TWO23[sx];
+                return t;
+            }
+            w = TWO23[sx]+x;
+            return w-TWO23[sx];
+        }
+        if(j0==0x80) return x+x;        /* inf or NaN */
+        else return x;                  /* x is integral */
+}
diff --git a/src/math/s_round.c b/src/math/s_round.c
new file mode 100644
index 00000000..d5bea7a9
--- /dev/null
+++ b/src/math/s_round.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003, Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+double
+round(double x)
+{
+	double t;
+
+	if (!isfinite(x))
+		return (x);
+
+	if (x >= 0.0) {
+		t = ceil(x);
+		if (t - x > 0.5)
+			t -= 1.0;
+		return (t);
+	} else {
+		t = ceil(-x);
+		if (t + x > 0.5)
+			t -= 1.0;
+		return (-t);
+	}
+}
diff --git a/src/math/s_roundf.c b/src/math/s_roundf.c
new file mode 100644
index 00000000..c4fc3e19
--- /dev/null
+++ b/src/math/s_roundf.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003, Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+float
+roundf(float x)
+{
+	float t;
+
+	if (!isfinite(x))
+		return (x);
+
+	if (x >= 0.0) {
+		t = ceilf(x);
+		if (t - x > 0.5)
+			t -= 1.0;
+		return (t);
+	} else {
+		t = ceilf(-x);
+		if (t + x > 0.5)
+			t -= 1.0;
+		return (-t);
+	}
+}
diff --git a/src/math/s_scalbln.c b/src/math/s_scalbln.c
new file mode 100644
index 00000000..12b9391b
--- /dev/null
+++ b/src/math/s_scalbln.c
@@ -0,0 +1,61 @@
+/* @(#)s_scalbn.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * scalbn (double x, int n)
+ * scalbn(x,n) returns x* 2**n  computed by  exponent
+ * manipulation rather than by actually performing an
+ * exponentiation or a multiplication.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+two54   =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54  =  5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+huge   = 1.0e+300,
+tiny   = 1.0e-300;
+
+double
+scalbln (double x, long n)
+{
+        int32_t k,hx,lx;
+        EXTRACT_WORDS(hx,lx,x);
+        k = (hx&0x7ff00000)>>20;                /* extract exponent */
+        if (k==0) {                             /* 0 or subnormal x */
+            if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+            x *= two54;
+            GET_HIGH_WORD(hx,x);
+            k = ((hx&0x7ff00000)>>20) - 54;
+            if (n< -50000) return tiny*x;       /*underflow*/
+            }
+        if (k==0x7ff) return x+x;               /* NaN or Inf */
+        k = k+n;
+        if (k >  0x7fe) return huge*copysign(huge,x); /* overflow  */
+        if (k > 0)                              /* normal result */
+            {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;}
+        if (k <= -54) {
+            if (n > 50000)      /* in case integer overflow in n+k */
+                return huge*copysign(huge,x);   /*overflow*/
+            else return tiny*copysign(tiny,x);  /*underflow*/
+        }
+        k += 54;                                /* subnormal result */
+        SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20));
+        return x*twom54;
+}
+
+double
+scalbn (double x, int n)
+{
+        return scalbln(x, n);
+}
diff --git a/src/math/s_scalblnf.c b/src/math/s_scalblnf.c
new file mode 100644
index 00000000..21e7641c
--- /dev/null
+++ b/src/math/s_scalblnf.c
@@ -0,0 +1,57 @@
+/* s_scalbnf.c -- float version of s_scalbn.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 <math.h>
+#include "math_private.h"
+
+static const float
+two25   =  3.355443200e+07,     /* 0x4c000000 */
+twom25  =  2.9802322388e-08,    /* 0x33000000 */
+huge   = 1.0e+30,
+tiny   = 1.0e-30;
+
+float
+scalblnf (float x, long n)
+{
+        int32_t k,ix;
+        GET_FLOAT_WORD(ix,x);
+        k = (ix&0x7f800000)>>23;                /* extract exponent */
+        if (k==0) {                             /* 0 or subnormal x */
+            if ((ix&0x7fffffff)==0) return x; /* +-0 */
+            x *= two25;
+            GET_FLOAT_WORD(ix,x);
+            k = ((ix&0x7f800000)>>23) - 25;
+            if (n< -50000) return tiny*x;       /*underflow*/
+            }
+        if (k==0xff) return x+x;                /* NaN or Inf */
+        k = k+n;
+        if (k >  0xfe) return huge*copysignf(huge,x); /* overflow  */
+        if (k > 0)                              /* normal result */
+            {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;}
+        if (k <= -25) {
+            if (n > 50000)      /* in case integer overflow in n+k */
+                return huge*copysignf(huge,x);  /*overflow*/
+            else return tiny*copysignf(tiny,x); /*underflow*/
+        }
+        k += 25;                                /* subnormal result */
+        SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23));
+        return x*twom25;
+}
+
+float
+scalbnf (float x, int n)
+{
+        return scalblnf(x, n);
+}
diff --git a/src/math/s_sin.c b/src/math/s_sin.c
new file mode 100644
index 00000000..2a2774ed
--- /dev/null
+++ b/src/math/s_sin.c
@@ -0,0 +1,74 @@
+/* @(#)s_sin.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* sin(x)
+ * Return sine function of x.
+ *
+ * kernel function:
+ *      __kernel_sin            ... sine function on [-pi/4,pi/4]
+ *      __kernel_cos            ... cose function on [-pi/4,pi/4]
+ *      __ieee754_rem_pio2      ... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on
+ *      [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ *      in [-pi/4 , +pi/4], and let n = k mod 4.
+ *      We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *          0          S           C             T
+ *          1          C          -S            -1/T
+ *          2         -S          -C             T
+ *          3         -C           S            -1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *      TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+sin(double x)
+{
+        double y[2],z=0.0;
+        int32_t n, ix;
+
+    /* High word of x. */
+        GET_HIGH_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
+
+    /* sin(Inf or NaN) is NaN */
+        else if (ix>=0x7ff00000) return x-x;
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2(x,y);
+            switch(n&3) {
+                case 0: return  __kernel_sin(y[0],y[1],1);
+                case 1: return  __kernel_cos(y[0],y[1]);
+                case 2: return -__kernel_sin(y[0],y[1],1);
+                default:
+                        return -__kernel_cos(y[0],y[1]);
+            }
+        }
+}
diff --git a/src/math/s_sinf.c b/src/math/s_sinf.c
new file mode 100644
index 00000000..d2b8e806
--- /dev/null
+++ b/src/math/s_sinf.c
@@ -0,0 +1,45 @@
+/* s_sinf.c -- float version of s_sin.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 <math.h>
+#include "math_private.h"
+
+float
+sinf(float x)
+{
+        float y[2],z=0.0;
+        int32_t n, ix;
+
+        GET_FLOAT_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0);
+
+    /* sin(Inf or NaN) is NaN */
+        else if (ix>=0x7f800000) return x-x;
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2f(x,y);
+            switch(n&3) {
+                case 0: return  __kernel_sinf(y[0],y[1],1);
+                case 1: return  __kernel_cosf(y[0],y[1]);
+                case 2: return -__kernel_sinf(y[0],y[1],1);
+                default:
+                        return -__kernel_cosf(y[0],y[1]);
+            }
+        }
+}
diff --git a/src/math/s_tan.c b/src/math/s_tan.c
new file mode 100644
index 00000000..3333cb3d
--- /dev/null
+++ b/src/math/s_tan.c
@@ -0,0 +1,68 @@
+/* @(#)s_tan.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* tan(x)
+ * Return tangent function of x.
+ *
+ * kernel function:
+ *      __kernel_tan            ... tangent function on [-pi/4,pi/4]
+ *      __ieee754_rem_pio2      ... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on
+ *      [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ *      in [-pi/4 , +pi/4], and let n = k mod 4.
+ *      We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *          0          S           C             T
+ *          1          C          -S            -1/T
+ *          2         -S          -C             T
+ *          3         -C           S            -1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *      TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+tan(double x)
+{
+        double y[2],z=0.0;
+        int32_t n, ix;
+
+    /* High word of x. */
+        GET_HIGH_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3fe921fb) return __kernel_tan(x,z,1);
+
+    /* tan(Inf or NaN) is NaN */
+        else if (ix>=0x7ff00000) return x-x;            /* NaN */
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2(x,y);
+            return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /*   1 -- n even
+                                                        -1 -- n odd */
+        }
+}
diff --git a/src/math/s_tanf.c b/src/math/s_tanf.c
new file mode 100644
index 00000000..660dd9c3
--- /dev/null
+++ b/src/math/s_tanf.c
@@ -0,0 +1,40 @@
+/* s_tanf.c -- float version of s_tan.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 <math.h>
+#include "math_private.h"
+
+float
+tanf(float x)
+{
+        float y[2],z=0.0;
+        int32_t n, ix;
+
+        GET_FLOAT_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3f490fda) return __kernel_tanf(x,z,1);
+
+    /* tan(Inf or NaN) is NaN */
+        else if (ix>=0x7f800000) return x-x;            /* NaN */
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2f(x,y);
+            return __kernel_tanf(y[0],y[1],1-((n&1)<<1)); /*   1 -- n even
+                                                              -1 -- n odd */
+        }
+}
diff --git a/src/math/s_tanh.c b/src/math/s_tanh.c
new file mode 100644
index 00000000..78b8e849
--- /dev/null
+++ b/src/math/s_tanh.c
@@ -0,0 +1,74 @@
+/* @(#)s_tanh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/* Tanh(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ *                                     x    -x
+ *                                    e  - e
+ *      0. tanh(x) is defined to be -----------
+ *                                     x    -x
+ *                                    e  + e
+ *      1. reduce x to non-negative by tanh(-x) = -tanh(x).
+ *      2.  0      <= x <= 2**-55 : tanh(x) := x*(one+x)
+ *                                              -t
+ *          2**-55 <  x <=  1     : tanh(x) := -----; t = expm1(-2x)
+ *                                             t + 2
+ *                                                   2
+ *          1      <= x <=  22.0  : tanh(x) := 1-  ----- ; t=expm1(2x)
+ *                                                 t + 2
+ *          22.0   <  x <= INF    : tanh(x) := 1.
+ *
+ * Special cases:
+ *      tanh(NaN) is NaN;
+ *      only tanh(0)=0 is exact for finite argument.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one=1.0, two=2.0, tiny = 1.0e-300;
+
+double
+tanh(double x)
+{
+        double t,z;
+        int32_t jx,ix;
+
+    /* High word of |x|. */
+        GET_HIGH_WORD(jx,x);
+        ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7ff00000) {
+            if (jx>=0) return one/x+one;    /* tanh(+-inf)=+-1 */
+            else       return one/x-one;    /* tanh(NaN) = NaN */
+        }
+
+    /* |x| < 22 */
+        if (ix < 0x40360000) {          /* |x|<22 */
+            if (ix<0x3c800000)          /* |x|<2**-55 */
+                return x*(one+x);       /* tanh(small) = small */
+            if (ix>=0x3ff00000) {       /* |x|>=1  */
+                t = expm1(two*fabs(x));
+                z = one - two/(t+two);
+            } else {
+                t = expm1(-two*fabs(x));
+                z= -t/(t+two);
+            }
+    /* |x| > 22, return +-1 */
+        } else {
+            z = one - tiny;             /* raised inexact flag */
+        }
+        return (jx>=0)? z: -z;
+}
diff --git a/src/math/s_tanhf.c b/src/math/s_tanhf.c
new file mode 100644
index 00000000..a0820409
--- /dev/null
+++ b/src/math/s_tanhf.c
@@ -0,0 +1,52 @@
+/* s_tanhf.c -- float version of s_tanh.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 <math.h>
+#include "math_private.h"
+
+static const float one=1.0, two=2.0, tiny = 1.0e-30;
+
+float
+tanhf(float x)
+{
+        float t,z;
+        int32_t jx,ix;
+
+        GET_FLOAT_WORD(jx,x);
+        ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7f800000) {
+            if (jx>=0) return one/x+one;    /* tanh(+-inf)=+-1 */
+            else       return one/x-one;    /* tanh(NaN) = NaN */
+        }
+
+    /* |x| < 22 */
+        if (ix < 0x41b00000) {          /* |x|<22 */
+            if (ix<0x24000000)          /* |x|<2**-55 */
+                return x*(one+x);       /* tanh(small) = small */
+            if (ix>=0x3f800000) {       /* |x|>=1  */
+                t = expm1f(two*fabsf(x));
+                z = one - two/(t+two);
+            } else {
+                t = expm1f(-two*fabsf(x));
+                z= -t/(t+two);
+            }
+    /* |x| > 22, return +-1 */
+        } else {
+            z = one - tiny;             /* raised inexact flag */
+        }
+        return (jx>=0)? z: -z;
+}
diff --git a/src/math/s_trunc.c b/src/math/s_trunc.c
new file mode 100644
index 00000000..02c65567
--- /dev/null
+++ b/src/math/s_trunc.c
@@ -0,0 +1,58 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * trunc(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ *      Bit twiddling.
+ * Exception:
+ *      Inexact flag raised if x not equal to trunc(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+double
+trunc(double x)
+{
+        int32_t i0,i1,j0;
+        uint32_t i,j;
+        EXTRACT_WORDS(i0,i1,x);
+        j0 = ((i0>>20)&0x7ff)-0x3ff;
+        if(j0<20) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>0.0) {/* |x|<1, so return 0*sign(x) */
+                    i0 &= 0x80000000U;
+                    i1 = 0;
+                }
+            } else {
+                i = (0x000fffff)>>j0;
+                if(((i0&i)|i1)==0) return x; /* x is integral */
+                if(huge+x>0.0) {        /* raise inexact flag */
+                    i0 &= (~i); i1=0;
+                }
+            }
+        } else if (j0>51) {
+            if(j0==0x400) return x+x;   /* inf or NaN */
+            else return x;              /* x is integral */
+        } else {
+            i = ((uint32_t)(0xffffffff))>>(j0-20);
+            if((i1&i)==0) return x;     /* x is integral */
+            if(huge+x>0.0)              /* raise inexact flag */
+                i1 &= (~i);
+        }
+        INSERT_WORDS(x,i0,i1);
+        return x;
+}
diff --git a/src/math/s_truncf.c b/src/math/s_truncf.c
new file mode 100644
index 00000000..c253e62b
--- /dev/null
+++ b/src/math/s_truncf.c
@@ -0,0 +1,50 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * truncf(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ *      Bit twiddling.
+ * Exception:
+ *      Inexact flag raised if x not equal to truncf(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float huge = 1.0e30F;
+
+float
+truncf(float x)
+{
+        int32_t i0,j0;
+        uint32_t i;
+        GET_FLOAT_WORD(i0,x);
+        j0 = ((i0>>23)&0xff)-0x7f;
+        if(j0<23) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>0.0F)         /* |x|<1, so return 0*sign(x) */
+                    i0 &= 0x80000000;
+            } else {
+                i = (0x007fffff)>>j0;
+                if((i0&i)==0) return x; /* x is integral */
+                if(huge+x>0.0F)         /* raise inexact flag */
+                    i0 &= (~i);
+            }
+        } else {
+            if(j0==0x80) return x+x;    /* inf or NaN */
+            else return x;              /* x is integral */
+        }
+        SET_FLOAT_WORD(x,i0);
+        return x;
+}