فهرست منبع

math: sinh.c cleanup similar to the cosh one

comments are kept in the double version of the function
Szabolcs Nagy 12 سال پیش
والد
کامیت
f143458223
3فایلهای تغییر یافته به همراه72 افزوده شده و 171 حذف شده
  1. 29 61
      src/math/sinh.c
  2. 20 46
      src/math/sinhf.c
  3. 23 64
      src/math/sinhl.c

+ 29 - 61
src/math/sinh.c

@@ -1,71 +1,39 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_sinh.c */
-/*
- * ====================================================
- * 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 "libm.h"
 
-static const double huge = 1.0e307;
-
+/* sinh(x) = (exp(x) - 1/exp(x))/2
+ *         = (exp(x)-1 + (exp(x)-1)/exp(x))/2
+ *         = x + x^3/6 + o(x^5)
+ */
 double sinh(double x)
 {
-	double t, h;
-	int32_t ix, jx;
-
-	/* High word of |x|. */
-	GET_HIGH_WORD(jx, x);
-	ix = jx & 0x7fffffff;
-
-	/* x is INF or NaN */
-	if (ix >= 0x7ff00000)
-		return x + x;
+	union {double f; uint64_t i;} u = {.f = x};
+	uint32_t w;
+	double t, h, absx;
 
 	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 */
-			/* raise inexact, return x */
-			if (huge+x > 1.0)
+	if (u.i >> 63)
+		h = -h;
+	/* |x| */
+	u.i &= (uint64_t)-1/2;
+	absx = u.f;
+	w = u.i >> 32;
+
+	/* |x| < log(DBL_MAX) */
+	if (w < 0x40862e42) {
+		t = expm1(absx);
+		if (w < 0x3ff00000) {
+			if (w < 0x3ff00000 - (26<<20))
+				/* note: inexact is raised by expm1 */
+				/* note: this branch avoids underflow */
 				return x;
-		t = expm1(fabs(x));
-		if (ix < 0x3ff00000)
-			return h*(2.0*t - t*t/(t+1.0));
-		return h*(t + t/(t+1.0));
+			return h*(2*t - t*t/(t+1));
+		}
+		/* note: |x|>log(0x1p26)+eps could be just h*exp(x) */
+		return h*(t + t/(t+1));
 	}
 
-	/* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
-	if (ix < 0x40862E42)
-		return h*exp(fabs(x));
-
-	/* |x| in [log(maxdouble), overflowthresold] */
-	if (ix <= 0x408633CE)
-		return h * 2.0 * __expo2(fabs(x)); /* h is for sign only */
-
-	/* |x| > overflowthresold, sinh(x) overflow */
-	return x*huge;
+	/* |x| > log(DBL_MAX) or nan */
+	/* note: the result is stored to handle overflow */
+	t = 2*h*__expo2(absx);
+	return t;
 }

+ 20 - 46
src/math/sinhf.c

@@ -1,57 +1,31 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_sinhf.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, [email protected].
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
 #include "libm.h"
 
-static const float huge = 1.0e37;
-
 float sinhf(float x)
 {
-	float t, h;
-	int32_t ix, jx;
-
-	GET_FLOAT_WORD(jx, x);
-	ix = jx & 0x7fffffff;
-
-	/* x is INF or NaN */
-	if (ix >= 0x7f800000)
-		return x + x;
+	union {float f; uint32_t i;} u = {.f = x};
+	uint32_t w;
+	float t, h, absx;
 
 	h = 0.5;
-	if (jx < 0)
+	if (u.i >> 31)
 		h = -h;
-	/* |x| in [0,9], return sign(x)*0.5*(E+E/(E+1))) */
-	if (ix < 0x41100000) {   /* |x|<9 */
-		if (ix < 0x39800000)  /* |x|<2**-12 */
-			/* raise inexact, return x */
-			if (huge+x > 1.0f)
+	/* |x| */
+	u.i &= 0x7fffffff;
+	absx = u.f;
+	w = u.i;
+
+	/* |x| < log(FLT_MAX) */
+	if (w < 0x42b17217) {
+		t = expm1f(absx);
+		if (w < 0x3f800000) {
+			if (w < 0x3f800000 - (12<<23))
 				return x;
-		t = expm1f(fabsf(x));
-		if (ix < 0x3f800000)
-			return h*(2.0f*t - t*t/(t+1.0f));
-		return h*(t + t/(t+1.0f));
+			return h*(2*t - t*t/(t+1));
+		}
+		return h*(t + t/(t+1));
 	}
 
-	/* |x| in [9, logf(maxfloat)] return 0.5*exp(|x|) */
-	if (ix < 0x42b17217)
-		return h*expf(fabsf(x));
-
-	/* |x| in [logf(maxfloat), overflowthresold] */
-	if (ix <= 0x42b2d4fc)
-		return h * 2.0f * __expo2f(fabsf(x)); /* h is for sign only */
-
-	/* |x| > overflowthresold, sinh(x) overflow */
-	return x*huge;
+	/* |x| > logf(FLT_MAX) or nan */
+	t = 2*h*__expo2f(absx);
+	return t;
 }

+ 23 - 64
src/math/sinhl.c

@@ -1,32 +1,3 @@
-/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_sinhl.c */
-/*
- * ====================================================
- * 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.
- * ====================================================
- */
-/* sinhl(x)
- * Method :
- * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
- *      1. Replace x by |x| (sinhl(-x) = -sinhl(x)).
- *      2.
- *                                                   E + E/(E+1)
- *          0        <= x <= 25     :  sinhl(x) := --------------, E=expm1l(x)
- *                                                       2
- *
- *          25       <= x <= lnovft :  sinhl(x) := expl(x)/2
- *          lnovft   <= x <= ln2ovft:  sinhl(x) := expl(x/2)/2 * expl(x/2)
- *          ln2ovft  <  x           :  sinhl(x) := x*huge (overflow)
- *
- * Special cases:
- *      sinhl(x) is |x| if x is +INF, -INF, or NaN.
- *      only sinhl(0)=0 is exact for finite x.
- */
-
 #include "libm.h"
 
 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
@@ -35,47 +6,35 @@ long double sinhl(long double x)
 	return sinh(x);
 }
 #elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
-static const long double huge = 1.0e4931L;
-
 long double sinhl(long double x)
 {
-	long double t,w,h;
-	uint32_t jx,ix,i0,i1;
-
-	/* Words of |x|. */
-	GET_LDOUBLE_WORDS(jx, i0, i1, x);
-	ix = jx & 0x7fff;
-
-	/* x is INF or NaN */
-	if (ix == 0x7fff) return x + x;
+	union {
+		long double f;
+		struct{uint64_t m; uint16_t se; uint16_t pad;} i;
+	} u = {.f = x};
+	unsigned ex = u.i.se & 0x7fff;
+	long double h, t, absx;
 
 	h = 0.5;
-	if (jx & 0x8000)
+	if (u.i.se & 0x8000)
 		h = -h;
-	/* |x| in [0,25], return sign(x)*0.5*(E+E/(E+1))) */
-	if (ix < 0x4003 || (ix == 0x4003 && i0 <= 0xc8000000)) { /* |x| < 25 */
-		if (ix < 0x3fdf)  /* |x|<2**-32 */
-			if (huge + x > 1.0)
-				return x;/* sinh(tiny) = tiny with inexact */
-		t = expm1l(fabsl(x));
-		if (ix < 0x3fff)
-			return h*(2.0*t - t*t/(t + 1.0));
-		return h*(t + t/(t + 1.0));
-	}
-
-	/* |x| in [25, log(maxdouble)] return 0.5*exp(|x|) */
-	if (ix < 0x400c || (ix == 0x400c && i0 < 0xb17217f7))
-		return h*expl(fabsl(x));
-
-	/* |x| in [log(maxdouble), overflowthreshold] */
-	if (ix < 0x400c || (ix == 0x400c && (i0 < 0xb174ddc0 ||
-	     (i0 == 0xb174ddc0 && i1 <= 0x31aec0ea)))) {
-		w = expl(0.5*fabsl(x));
-		t = h*w;
-		return t*w;
+	/* |x| */
+	u.i.se = ex;
+	absx = u.f;
+
+	/* |x| < log(LDBL_MAX) */
+	if (ex < 0x3fff+13 || (ex == 0x3fff+13 && u.i.m>>32 < 0xb17217f7)) {
+		t = expm1l(absx);
+		if (ex < 0x3fff) {
+			if (ex < 0x3fff-32)
+				return x;
+			return h*(2*t - t*t/(1+t));
+		}
+		return h*(t + t/(t+1));
 	}
 
-	/* |x| > overflowthreshold, sinhl(x) overflow */
-	return x*huge;
+	/* |x| > log(LDBL_MAX) or nan */
+	t = expl(0.5*absx);
+	return h*t*t;
 }
 #endif