diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/math/j1.c | 172 | ||||
| -rw-r--r-- | src/math/j1f.c | 153 | 
2 files changed, 138 insertions, 187 deletions
| diff --git a/src/math/j1.c b/src/math/j1.c index 4a2cba8d..ac7bb1eb 100644 --- a/src/math/j1.c +++ b/src/math/j1.c @@ -59,10 +59,47 @@  static double pone(double), qone(double);  static const double -huge      = 1e300,  invsqrtpi = 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ -tpi       = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +tpi       = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +static double common(uint32_t ix, double x, int y1, int sign) +{ +	double z,s,c,ss,cc; + +	/* +	 * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) +	 * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) +	 * +	 * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) +	 * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) +	 * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) +	 */ +	s = sin(x); +	if (y1) +		s = -s; +	c = cos(x); +	cc = s-c; +	if (ix < 0x7fe00000) { +		/* avoid overflow in 2*x */ +		ss = -s-c; +		z = cos(2*x); +		if (s*c > 0) +			cc = z/ss; +		else +			ss = z/cc; +		if (ix < 0x48000000) { +			if (y1) +				ss = -ss; +			cc = pone(x)*cc-qone(x)*ss; +		} +	} +	if (sign) +		cc = -cc; +	return invsqrtpi*cc/sqrt(x); +} +  /* R0/S0 on [0,2] */ +static const double  r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */  r01 =  1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */  r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */ @@ -75,52 +112,26 @@ s05 =  1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */  double j1(double x)  { -	double z,s,c,ss,cc,r,u,v,y; -	int32_t hx,ix; +	double z,r,s; +	uint32_t ix; +	int sign; -	GET_HIGH_WORD(hx, x); -	ix = hx & 0x7fffffff; +	GET_HIGH_WORD(ix, x); +	sign = ix>>31; +	ix &= 0x7fffffff;  	if (ix >= 0x7ff00000) -		return 1.0/x; -	y = fabs(x); -	if (ix >= 0x40000000) {  /* |x| >= 2.0 */ -		s = sin(y); -		c = cos(y); -		ss = -s-c; -		cc = s-c; -		if (ix < 0x7fe00000) {  /* make sure y+y not overflow */ -			z = cos(y+y); -			if (s*c > 0.0) -				cc = z/ss; -			else -				ss = z/cc; -		} -		/* -		 * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x) -		 * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x) -		 */ -		if (ix > 0x48000000) -			z = (invsqrtpi*cc)/sqrt(y); -		else { -			u = pone(y); -			v = qone(y); -			z = invsqrtpi*(u*cc-v*ss)/sqrt(y); -		} -		if (hx < 0) -			return -z; -		else -			return  z; -	} -	if (ix < 0x3e400000) {  /* |x| < 2**-27 */ -		/* raise inexact if x!=0 */ -		if (huge+x > 1.0) -			return 0.5*x; -	} -	z = x*x; -	r = z*(r00+z*(r01+z*(r02+z*r03))); -	s = 1.0+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); -	r *= x; -	return x*0.5 + r/s; +		return 1/(x*x); +	if (ix >= 0x40000000)  /* |x| >= 2 */ +		return common(ix, fabs(x), 0, sign); +	if (ix >= 0x38000000) {  /* |x| >= 2**-127 */ +		z = x*x; +		r = z*(r00+z*(r01+z*(r02+z*r03))); +		s = 1+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); +		z = r/s; +	} else +		/* avoid underflow, raise inexact if x!=0 */ +		z = x; +	return (0.5 + z)*x;  }  static const double U0[5] = { @@ -138,59 +149,28 @@ static const double V0[5] = {    1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */  }; -  double y1(double x)  { -	double z,s,c,ss,cc,u,v; -	int32_t hx,ix,lx; +	double z,u,v; +	uint32_t ix,lx; -	EXTRACT_WORDS(hx, lx, x); -	ix = 0x7fffffff & hx; -	/* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */ +	EXTRACT_WORDS(ix, lx, x); +	/* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ +	if ((ix<<1 | lx) == 0) +		return -1/0.0; +	if (ix>>31) +		return 0/0.0;  	if (ix >= 0x7ff00000) -		return 1.0/(x+x*x); -	if ((ix|lx) == 0) -		return -1.0/0.0; -	if (hx < 0) -		return 0.0/0.0; -	if (ix >= 0x40000000) {  /* |x| >= 2.0 */ -		s = sin(x); -		c = cos(x); -		ss = -s-c; -		cc = s-c; -		if (ix < 0x7fe00000) {  /* make sure x+x not overflow */ -			z = cos(x+x); -			if (s*c > 0.0) -				cc = z/ss; -			else -				ss = z/cc; -		} -		/* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0)) -		 * where x0 = x-3pi/4 -		 *      Better formula: -		 *              cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) -		 *                      =  1/sqrt(2) * (sin(x) - cos(x)) -		 *              sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) -		 *                      = -1/sqrt(2) * (cos(x) + sin(x)) -		 * To avoid cancellation, use -		 *              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) -		 * to compute the worse one. -		 */ -		if (ix > 0x48000000) -			z = (invsqrtpi*ss)/sqrt(x); -		else { -			u = pone(x); -			v = qone(x); -			z = invsqrtpi*(u*ss+v*cc)/sqrt(x); -		} -		return z; -	} -	if (ix <= 0x3c900000)  /* x < 2**-54 */ +		return 1/x; + +	if (ix >= 0x40000000)  /* x >= 2 */ +		return common(ix, x, 1, 0); +	if (ix < 0x3c900000)  /* x < 2**-54 */  		return -tpi/x;  	z = x*x;  	u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); -	v = 1.0+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); -	return x*(u/v) + tpi*(j1(x)*log(x)-1.0/x); +	v = 1+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); +	return x*(u/v) + tpi*(j1(x)*log(x)-1/x);  }  /* For x >= 8, the asymptotic expansions of pone is @@ -271,14 +251,14 @@ static double pone(double x)  {  	const double *p,*q;  	double z,r,s; -	int32_t ix; +	uint32_t ix;  	GET_HIGH_WORD(ix, x);  	ix &= 0x7fffffff;  	if      (ix >= 0x40200000){p = pr8; q = ps8;}  	else if (ix >= 0x40122E8B){p = pr5; q = ps5;}  	else if (ix >= 0x4006DB6D){p = pr3; q = ps3;} -	else if (ix >= 0x40000000){p = pr2; q = ps2;} +	else /*ix >= 0x40000000*/ {p = pr2; q = ps2;}  	z = 1.0/(x*x);  	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));  	s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); @@ -367,14 +347,14 @@ static double qone(double x)  {  	const double *p,*q;  	double  s,r,z; -	int32_t ix; +	uint32_t ix;  	GET_HIGH_WORD(ix, x);  	ix &= 0x7fffffff;  	if      (ix >= 0x40200000){p = qr8; q = qs8;}  	else if (ix >= 0x40122E8B){p = qr5; q = qs5;}  	else if (ix >= 0x4006DB6D){p = qr3; q = qs3;} -	else if (ix >= 0x40000000){p = qr2; q = qs2;} +	else /*ix >= 0x40000000*/ {p = qr2; q = qs2;}  	z = 1.0/(x*x);  	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));  	s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); diff --git a/src/math/j1f.c b/src/math/j1f.c index de459e0d..5a760f71 100644 --- a/src/math/j1f.c +++ b/src/math/j1f.c @@ -18,10 +18,38 @@  static float ponef(float), qonef(float);  static const float -huge      = 1e30,  invsqrtpi = 5.6418961287e-01, /* 0x3f106ebb */ -tpi       = 6.3661974669e-01, /* 0x3f22f983 */ +tpi       = 6.3661974669e-01; /* 0x3f22f983 */ + +static float common(uint32_t ix, float x, int y1, int sign) +{ +	double z,s,c,ss,cc; + +	s = sinf(x); +	if (y1) +		s = -s; +	c = cosf(x); +	cc = s-c; +	if (ix < 0x7f000000) { +		ss = -s-c; +		z = cosf(2*x); +		if (s*c > 0) +			cc = z/ss; +		else +			ss = z/cc; +		if (ix < 0x58800000) { +			if (y1) +				ss = -ss; +			cc = ponef(x)*cc-qonef(x)*ss; +		} +	} +	if (sign) +		cc = -cc; +	return invsqrtpi*cc/sqrtf(x); +} +  /* R0/S0 on [0,2] */ +static const float  r00 = -6.2500000000e-02, /* 0xbd800000 */  r01 =  1.4070566976e-03, /* 0x3ab86cfd */  r02 = -1.5995563444e-05, /* 0xb7862e36 */ @@ -34,51 +62,26 @@ s05 =  1.2354227016e-11; /* 0x2d59567e */  float j1f(float x)  { -	float z,s,c,ss,cc,r,u,v,y; -	int32_t hx,ix; +	float z,r,s; +	uint32_t ix; +	int sign; -	GET_FLOAT_WORD(hx, x); -	ix = hx & 0x7fffffff; +	GET_FLOAT_WORD(ix, x); +	sign = ix>>31; +	ix &= 0x7fffffff;  	if (ix >= 0x7f800000) -		return 1.0f/x; -	y = fabsf(x); -	if (ix >= 0x40000000) {  /* |x| >= 2.0 */ -		s = sinf(y); -		c = cosf(y); -		ss = -s-c; -		cc = s-c; -		if (ix < 0x7f000000) {  /* make sure y+y not overflow */ -			z = cosf(y+y); -			if (s*c > 0.0f) -				cc = z/ss; -			else -				ss = z/cc; -		} -		/* -		 * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x) -		 * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x) -		 */ -		if (ix > 0x80000000) -			z = (invsqrtpi*cc)/sqrtf(y); -		else { -			u = ponef(y); -			v = qonef(y); -			z = invsqrtpi*(u*cc-v*ss)/sqrtf(y); -		} -		if (hx < 0) -			return -z; -		return  z; -	} -	if (ix < 0x32000000) {  /* |x| < 2**-27 */ +		return 1/(x*x); +	if (ix >= 0x40000000)  /* |x| >= 2 */ +		return common(ix, fabsf(x), 0, sign); +	if (ix >= 0x32000000) {  /* |x| >= 2**-27 */ +		z = x*x; +		r = z*(r00+z*(r01+z*(r02+z*r03))); +		s = 1+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); +		z = 0.5f + r/s; +	} else  		/* raise inexact if x!=0 */ -		if (huge+x > 1.0f) -			return 0.5f*x; -	} -	z = x*x; -	r = z*(r00+z*(r01+z*(r02+z*r03))); -	s = 1.0f+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); -	r *= x; -	return 0.5f*x + r/s; +		z = 0.5f + x; +	return z*x;  }  static const float U0[5] = { @@ -98,51 +101,19 @@ static const float V0[5] = {  float y1f(float x)  { -	float z,s,c,ss,cc,u,v; -	int32_t hx,ix; +	float z,u,v; +	uint32_t ix; -	GET_FLOAT_WORD(hx, x); -	ix = 0x7fffffff & hx; -	/* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */ +	GET_FLOAT_WORD(ix, x); +	if ((ix & 0x7fffffff) == 0) +		return -1/0.0f; +	if (ix>>31) +		return 0/0.0f;  	if (ix >= 0x7f800000) -		return 1.0f/(x+x*x); -	if (ix == 0) -		return -1.0f/0.0f; -	if (hx < 0) -		return 0.0f/0.0f; -	if (ix >= 0x40000000) {  /* |x| >= 2.0 */ -		s = sinf(x); -		c = cosf(x); -		ss = -s-c; -		cc = s-c; -		if (ix < 0x7f000000) {  /* make sure x+x not overflow */ -			z = cosf(x+x); -			if (s*c > 0.0f) -				cc = z/ss; -			else -				ss = z/cc; -		} -		/* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0)) -		 * where x0 = x-3pi/4 -		 *      Better formula: -		 *              cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) -		 *                      =  1/sqrt(2) * (sin(x) - cos(x)) -		 *              sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) -		 *                      = -1/sqrt(2) * (cos(x) + sin(x)) -		 * To avoid cancellation, use -		 *              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) -		 * to compute the worse one. -		 */ -		if (ix > 0x48000000) -			z = (invsqrtpi*ss)/sqrtf(x); -		else { -			u = ponef(x); -			v = qonef(x); -			z = invsqrtpi*(u*ss+v*cc)/sqrtf(x); -		} -		return z; -	} -	if (ix <= 0x24800000)  /* x < 2**-54 */ +		return 1/x; +	if (ix >= 0x40000000)  /* |x| >= 2.0 */ +		return common(ix,x,1,0); +	if (ix < 0x32000000)  /* x < 2**-27 */  		return -tpi/x;  	z = x*x;  	u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); @@ -228,14 +199,14 @@ static float ponef(float x)  {  	const float *p,*q;  	float z,r,s; -	int32_t ix; +	uint32_t ix;  	GET_FLOAT_WORD(ix, x);  	ix &= 0x7fffffff;  	if      (ix >= 0x41000000){p = pr8; q = ps8;}  	else if (ix >= 0x40f71c58){p = pr5; q = ps5;}  	else if (ix >= 0x4036db68){p = pr3; q = ps3;} -	else if (ix >= 0x40000000){p = pr2; q = ps2;} +	else /*ix >= 0x40000000*/ {p = pr2; q = ps2;}  	z = 1.0f/(x*x);  	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));  	s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); @@ -324,14 +295,14 @@ static float qonef(float x)  {  	const float *p,*q;  	float s,r,z; -	int32_t ix; +	uint32_t ix;  	GET_FLOAT_WORD(ix, x);  	ix &= 0x7fffffff;  	if      (ix >= 0x40200000){p = qr8; q = qs8;}  	else if (ix >= 0x40f71c58){p = qr5; q = qs5;}  	else if (ix >= 0x4036db68){p = qr3; q = qs3;} -	else if (ix >= 0x40000000){p = qr2; q = qs2;} +	else /*ix >= 0x40000000*/ {p = qr2; q = qs2;}  	z = 1.0f/(x*x);  	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));  	s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); | 
