diff options
Diffstat (limited to 'src/math')
| -rw-r--r-- | src/math/cosh.c | 41 | ||||
| -rw-r--r-- | src/math/coshf.c | 37 | ||||
| -rw-r--r-- | src/math/coshl.c | 55 | 
3 files changed, 63 insertions, 70 deletions
| diff --git a/src/math/cosh.c b/src/math/cosh.c index a1f7dbc7..2fcdea8f 100644 --- a/src/math/cosh.c +++ b/src/math/cosh.c @@ -23,7 +23,7 @@   *                                                        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) + *          ln2ovft  <  x           :  cosh(x) := inf (overflow)   *   * Special cases:   *      cosh(x) is |x| if x is +INF, -INF, or NaN. @@ -32,43 +32,40 @@  #include "libm.h" -static const double huge = 1.0e300; -  double cosh(double x)  { -	double t, w; -	int32_t ix; - -	GET_HIGH_WORD(ix, x); -	ix &= 0x7fffffff; +	union {double f; uint64_t i;} u = {.f = x}; +	uint32_t ix; +	double t; -	/* x is INF or NaN */ -	if (ix >= 0x7ff00000) -		return x*x; +	/* |x| */ +	u.i &= (uint64_t)-1/2; +	x = u.f; +	ix = u.i >> 32;  	/* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */  	if (ix < 0x3fd62e43) { -		t = expm1(fabs(x)); -		w = 1.0+t; +		t = expm1(x);  		if (ix < 0x3c800000) -			return w;  /* cosh(tiny) = 1 */ -		return 1.0 + (t*t)/(w+w); +			return 1; +		return 1 + t*t/(2*(1+t));  	}  	/* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|))/2; */  	if (ix < 0x40360000) { -		t = exp(fabs(x)); +		t = exp(x);  		return 0.5*t + 0.5/t;  	}  	/* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */ -	if (ix < 0x40862E42) -		return 0.5*exp(fabs(x)); +	if (ix < 0x40862e42) +		return 0.5*exp(x);  	/* |x| in [log(maxdouble), overflowthresold] */ -	if (ix <= 0x408633CE) -		return __expo2(fabs(x)); +	if (ix <= 0x408633ce) +		return __expo2(x); -	/* |x| > overflowthresold, cosh(x) overflow */ -	return huge*huge; +	/* overflow (or nan) */ +	x *= 0x1p1023; +	return x;  } diff --git a/src/math/coshf.c b/src/math/coshf.c index 97318f10..2bed1258 100644 --- a/src/math/coshf.c +++ b/src/math/coshf.c @@ -15,43 +15,40 @@  #include "libm.h" -static const float huge = 1.0e30; -  float coshf(float x)  { -	float t, w; -	int32_t ix; - -	GET_FLOAT_WORD(ix, x); -	ix &= 0x7fffffff; +	union {float f; uint32_t i;} u = {.f = x}; +	uint32_t ix; +	float t; -	/* x is INF or NaN */ -	if (ix >= 0x7f800000) -		return x*x; +	/* |x| */ +	u.i &= 0x7fffffff; +	x = u.f; +	ix = u.i;  	/* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */  	if (ix < 0x3eb17218) { -		t = expm1f(fabsf(x)); -		w = 1.0f+t; -		if (ix<0x39800000) -			return 1.0f;  /* cosh(tiny) = 1 */ -		return 1.0f + (t*t)/(w+w); +		t = expm1f(x); +		if (ix < 0x39800000) +			return 1; +		return 1 + t*t/(2*(1+t));  	}  	/* |x| in [0.5*ln2,9], return (exp(|x|)+1/exp(|x|))/2; */  	if (ix < 0x41100000) { -		t = expf(fabsf(x)); +		t = expf(x);  		return 0.5f*t + 0.5f/t;  	}  	/* |x| in [9, log(maxfloat)] return 0.5f*exp(|x|) */  	if (ix < 0x42b17217) -		return 0.5f*expf(fabsf(x)); +		return 0.5f*expf(x);  	/* |x| in [log(maxfloat), overflowthresold] */  	if (ix <= 0x42b2d4fc) -		return __expo2f(fabsf(x)); +		return __expo2f(x); -	/* |x| > overflowthresold, cosh(x) overflow */ -	return huge*huge; +	/* |x| > overflowthresold or nan */ +	x *= 0x1p127f; +	return x;  } diff --git a/src/math/coshl.c b/src/math/coshl.c index 36b52c02..3ea56e00 100644 --- a/src/math/coshl.c +++ b/src/math/coshl.c @@ -23,7 +23,7 @@   *                                                         2   *          22       <= x <= lnovft :  coshl(x) := expl(x)/2   *          lnovft   <= x <= ln2ovft:  coshl(x) := expl(x/2)/2 * expl(x/2) - *          ln2ovft  <  x           :  coshl(x) := huge*huge (overflow) + *          ln2ovft  <  x           :  coshl(x) := inf (overflow)   *   * Special cases:   *      coshl(x) is |x| if x is +INF, -INF, or NaN. @@ -38,49 +38,48 @@ long double coshl(long double x)  	return cosh(x);  }  #elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 -static const long double huge = 1.0e4900L; -  long double coshl(long double x)  { -	long double t,w; -	int32_t ex; +	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 t;  	uint32_t mx,lx; -	/* High word of |x|. */ -	GET_LDOUBLE_WORDS(ex, mx, lx, x); -	ex &= 0x7fff; - -	/* x is INF or NaN */ -	if (ex == 0x7fff) return x*x; +	/* |x| */ +	u.i.se = ex; +	x = u.f; +	mx = u.i.m >> 32; +	lx = u.i.m;  	/* |x| in [0,0.5*ln2], return 1+expm1l(|x|)^2/(2*expl(|x|)) */ -	if (ex < 0x3ffd || (ex == 0x3ffd && mx < 0xb17217f7u)) { -		t = expm1l(fabsl(x)); -		w = 1.0 + t; -		if (ex < 0x3fbc) return w;    /* cosh(tiny) = 1 */ -		return 1.0+(t*t)/(w+w); +	if (ex < 0x3fff-2 || (ex == 0x3fff-2 && mx < 0xb17217f7)) { +		t = expm1l(x); +		if (ex < 0x3fff-64) +			return 1; +		return 1 + t*t/(2*(1+t));  	}  	/* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */ -	if (ex < 0x4003 || (ex == 0x4003 && mx < 0xb0000000u)) { -		t = expl(fabsl(x)); +	if (ex < 0x3fff+4 || (ex == 0x3fff+4 && mx < 0xb0000000)) { +		t = expl(x);  		return 0.5*t + 0.5/t;  	}  	/* |x| in [22, ln(maxdouble)] return 0.5*exp(|x|) */ -	if (ex < 0x400c || (ex == 0x400c && mx < 0xb1700000u)) -		return 0.5*expl(fabsl(x)); +	if (ex < 0x3fff+13 || (ex == 0x3fff+13 && mx < 0xb1700000)) +		return 0.5*expl(x);  	/* |x| in [log(maxdouble), log(2*maxdouble)) */ -	if (ex == 0x400c && (mx < 0xb174ddc0u || -	     (mx == 0xb174ddc0u && lx < 0x31aec0ebu))) -	{ -		w = expl(0.5*fabsl(x)); -		t = 0.5*w; -		return t*w; +	if (ex == 0x3fff+13 && (mx < 0xb174ddc0 || +	     (mx == 0xb174ddc0 && lx < 0x31aec0eb))) { +		t = expl(0.5*x); +		return 0.5*t*t;  	} -	/* |x| >= log(2*maxdouble), cosh(x) overflow */ -	return huge*huge; +	/* |x| >= log(2*maxdouble) or nan */ +	return x*0x1p16383L;  }  #endif | 
