فهرست منبع

math: expf.c cleanup

similar to exp.c cleanup: use scalbnf, don't return excess precision,
drop some optimizatoins.
exp.c was changed to be more consistent with expf.c code.
Szabolcs Nagy 12 سال پیش
والد
کامیت
ab1772c597
2فایلهای تغییر یافته به همراه55 افزوده شده و 63 حذف شده
  1. 11 9
      src/math/exp.c
  2. 44 54
      src/math/expf.c

+ 11 - 9
src/math/exp.c

@@ -80,7 +80,7 @@ P5   =  4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
 
 double exp(double x)
 {
-	double hi, lo, c, z;
+	double hi, lo, c, xx;
 	int k, sign;
 	uint32_t hx;
 
@@ -92,24 +92,26 @@ double exp(double x)
 	if (hx >= 0x40862e42) {  /* if |x| >= 709.78... */
 		if (isnan(x))
 			return x;
+		if (hx == 0x7ff00000 && sign) /* -inf */
+			return 0;
 		if (x > 709.782712893383973096) {
 			/* overflow if x!=inf */
 			STRICT_ASSIGN(double, x, 0x1p1023 * x);
 			return x;
 		}
 		if (x < -745.13321910194110842) {
-			/* underflow if x!=-inf */
-			STRICT_ASSIGN(double, x, 0x1p-1000 / -x * 0x1p-1000);
+			/* underflow */
+			STRICT_ASSIGN(double, x, 0x1p-1000 * 0x1p-1000);
 			return x;
 		}
 	}
 
 	/* argument reduction */
 	if (hx > 0x3fd62e42) {  /* if |x| > 0.5 ln2 */
-		if (hx < 0x3ff0a2b2)  /* if |x| < 1.5 ln2 */
-			k = 1 - sign - sign; /* optimization */
-		else
+		if (hx >= 0x3ff0a2b2)  /* if |x| >= 1.5 ln2 */
 			k = (int)(invln2*x + half[sign]);
+		else
+			k = 1 - sign - sign;
 		hi = x - k*ln2hi;  /* k*ln2hi is exact here */
 		lo = k*ln2lo;
 		STRICT_ASSIGN(double, x, hi - lo);
@@ -124,9 +126,9 @@ double exp(double x)
 	}
 
 	/* x is now in primary range */
-	z = x*x;
-	c = x - z*(P1+z*(P2+z*(P3+z*(P4+z*P5))));
-	x = 1 + ((x*c/(2-c) - lo) + hi);
+	xx = x*x;
+	c = x - xx*(P1+xx*(P2+xx*(P3+xx*(P4+xx*P5))));
+	x = 1 + (x*c/(2-c) - lo + hi);
 	if (k == 0)
 		return x;
 	return scalbn(x, k);

+ 44 - 54
src/math/expf.c

@@ -16,79 +16,69 @@
 #include "libm.h"
 
 static const float
-halF[2] = {0.5,-0.5,},
-huge    = 1.0e+30,
-o_threshold =  8.8721679688e+01,  /* 0x42b17180 */
-u_threshold = -1.0397208405e+02,  /* 0xc2cff1b5 */
-ln2HI[2]   = { 6.9314575195e-01,  /* 0x3f317200 */
-              -6.9314575195e-01,},/* 0xbf317200 */
-ln2LO[2]   = { 1.4286067653e-06,  /* 0x35bfbe8e */
-              -1.4286067653e-06,},/* 0xb5bfbe8e */
-invln2 = 1.4426950216e+00,        /* 0x3fb8aa3b */
+half[2] = {0.5,-0.5},
+ln2hi   = 6.9314575195e-1f,  /* 0x3f317200 */
+ln2lo   = 1.4286067653e-6f,  /* 0x35bfbe8e */
+invln2  = 1.4426950216e+0f,  /* 0x3fb8aa3b */
 /*
  * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]:
  * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74
  */
-P1 =  1.6666625440e-1, /*  0xaaaa8f.0p-26 */
-P2 = -2.7667332906e-3; /* -0xb55215.0p-32 */
-
-static const volatile float twom100 = 7.8886090522e-31; /* 2**-100=0x0d800000 */
+P1 =  1.6666625440e-1f, /*  0xaaaa8f.0p-26 */
+P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */
 
 float expf(float x)
 {
-	float y,hi=0.0,lo=0.0,c,t,twopk;
-	int32_t k=0,xsb;
+	float hi, lo, c, xx;
+	int k, sign;
 	uint32_t hx;
 
 	GET_FLOAT_WORD(hx, x);
-	xsb = (hx>>31)&1;  /* sign bit of x */
+	sign = hx >> 31;   /* sign bit of x */
 	hx &= 0x7fffffff;  /* high word of |x| */
 
-	/* filter out non-finite argument */
-	if (hx >= 0x42b17218) {  /* if |x|>=88.721... */
+	/* special cases */
+	if (hx >= 0x42b17218) {  /* if |x| >= 88.722839f or NaN */
 		if (hx > 0x7f800000)  /* NaN */
-			return x+x;
-		if (hx == 0x7f800000)  /* exp(+-inf)={inf,0} */
-			return xsb==0 ? x : 0.0;
-		if (x > o_threshold)
-			return huge*huge; /* overflow */
-		if (x < u_threshold)
-			return twom100*twom100; /* underflow */
+			return x;
+		if (!sign) {
+			/* overflow if x!=inf */
+			STRICT_ASSIGN(float, x, x * 0x1p127f);
+			return x;
+		}
+		if (hx == 0x7f800000)  /* -inf */
+			return 0;
+		if (hx >= 0x42cff1b5) { /* x <= -103.972084f */
+			/* underflow */
+			STRICT_ASSIGN(float, x, 0x1p-100f*0x1p-100f);
+			return x;
+		}
 	}
 
 	/* 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];
-		}
+	if (hx > 0x3eb17218) {  /* if |x| > 0.5 ln2 */
+		if (hx > 0x3f851592)  /* if |x| > 1.5 ln2 */
+			k = invln2*x + half[sign];
+		else
+			k = 1 - sign - sign;
+		hi = x - k*ln2hi;  /* k*ln2hi is exact here */
+		lo = k*ln2lo;
 		STRICT_ASSIGN(float, x, hi - lo);
-	} else if(hx < 0x39000000)  {  /* |x|<2**-14 */
-		/* raise inexact */
-		if (huge+x > 1.0f)
-			return 1.0f + x;
-	} else
+	} else if (hx > 0x39000000) {  /* |x| > 2**-14 */
 		k = 0;
+		hi = x;
+		lo = 0;
+	} else {
+		/* raise inexact */
+		FORCE_EVAL(0x1p127f + x);
+		return 1 + x;
+	}
 
 	/* x is now in primary range */
-	t = x*x;
-	if (k >= -125)
-		SET_FLOAT_WORD(twopk, 0x3f800000+(k<<23));
-	else
-		SET_FLOAT_WORD(twopk, 0x3f800000+((k+100)<<23));
-	c  = x - t*(P1+t*P2);
+	xx = x*x;
+	c = x - xx*(P1+xx*P2);
+	x = 1 + (x*c/(2-c) - lo + hi);
 	if (k == 0)
-		return 1.0f - ((x*c)/(c - 2.0f) - x);
-	y = 1.0f - ((lo - (x*c)/(2.0f - c)) - hi);
-	if (k < -125)
-		return y*twopk*twom100;
-	if (k == 128)
-		return y*2.0f*0x1p127f;
-	return y*twopk;
+		return x;
+	return scalbnf(x, k);
 }