xref: /freebsd/lib/msun/src/e_jnf.c (revision 3a8617a83f16ffc9db4f96e1f0f21af94078e6b1)
13a8617a8SJordan K. Hubbard /* e_jnf.c -- float version of e_jn.c.
23a8617a8SJordan K. Hubbard  * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
33a8617a8SJordan K. Hubbard  */
43a8617a8SJordan K. Hubbard 
53a8617a8SJordan K. Hubbard /*
63a8617a8SJordan K. Hubbard  * ====================================================
73a8617a8SJordan K. Hubbard  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
83a8617a8SJordan K. Hubbard  *
93a8617a8SJordan K. Hubbard  * Developed at SunPro, a Sun Microsystems, Inc. business.
103a8617a8SJordan K. Hubbard  * Permission to use, copy, modify, and distribute this
113a8617a8SJordan K. Hubbard  * software is freely granted, provided that this notice
123a8617a8SJordan K. Hubbard  * is preserved.
133a8617a8SJordan K. Hubbard  * ====================================================
143a8617a8SJordan K. Hubbard  */
153a8617a8SJordan K. Hubbard 
163a8617a8SJordan K. Hubbard #ifndef lint
173a8617a8SJordan K. Hubbard static char rcsid[] = "$Id: e_jnf.c,v 1.2 1994/08/18 23:05:39 jtc Exp $";
183a8617a8SJordan K. Hubbard #endif
193a8617a8SJordan K. Hubbard 
203a8617a8SJordan K. Hubbard #include "math.h"
213a8617a8SJordan K. Hubbard #include "math_private.h"
223a8617a8SJordan K. Hubbard 
233a8617a8SJordan K. Hubbard #ifdef __STDC__
243a8617a8SJordan K. Hubbard static const float
253a8617a8SJordan K. Hubbard #else
263a8617a8SJordan K. Hubbard static float
273a8617a8SJordan K. Hubbard #endif
283a8617a8SJordan K. Hubbard invsqrtpi=  5.6418961287e-01, /* 0x3f106ebb */
293a8617a8SJordan K. Hubbard two   =  2.0000000000e+00, /* 0x40000000 */
303a8617a8SJordan K. Hubbard one   =  1.0000000000e+00; /* 0x3F800000 */
313a8617a8SJordan K. Hubbard 
323a8617a8SJordan K. Hubbard #ifdef __STDC__
333a8617a8SJordan K. Hubbard static const float zero  =  0.0000000000e+00;
343a8617a8SJordan K. Hubbard #else
353a8617a8SJordan K. Hubbard static float zero  =  0.0000000000e+00;
363a8617a8SJordan K. Hubbard #endif
373a8617a8SJordan K. Hubbard 
383a8617a8SJordan K. Hubbard #ifdef __STDC__
393a8617a8SJordan K. Hubbard 	float __ieee754_jnf(int n, float x)
403a8617a8SJordan K. Hubbard #else
413a8617a8SJordan K. Hubbard 	float __ieee754_jnf(n,x)
423a8617a8SJordan K. Hubbard 	int n; float x;
433a8617a8SJordan K. Hubbard #endif
443a8617a8SJordan K. Hubbard {
453a8617a8SJordan K. Hubbard 	int32_t i,hx,ix, sgn;
463a8617a8SJordan K. Hubbard 	float a, b, temp, di;
473a8617a8SJordan K. Hubbard 	float z, w;
483a8617a8SJordan K. Hubbard 
493a8617a8SJordan K. Hubbard     /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
503a8617a8SJordan K. Hubbard      * Thus, J(-n,x) = J(n,-x)
513a8617a8SJordan K. Hubbard      */
523a8617a8SJordan K. Hubbard 	GET_FLOAT_WORD(hx,x);
533a8617a8SJordan K. Hubbard 	ix = 0x7fffffff&hx;
543a8617a8SJordan K. Hubbard     /* if J(n,NaN) is NaN */
553a8617a8SJordan K. Hubbard 	if(ix>0x7f800000) return x+x;
563a8617a8SJordan K. Hubbard 	if(n<0){
573a8617a8SJordan K. Hubbard 		n = -n;
583a8617a8SJordan K. Hubbard 		x = -x;
593a8617a8SJordan K. Hubbard 		hx ^= 0x80000000;
603a8617a8SJordan K. Hubbard 	}
613a8617a8SJordan K. Hubbard 	if(n==0) return(__ieee754_j0f(x));
623a8617a8SJordan K. Hubbard 	if(n==1) return(__ieee754_j1f(x));
633a8617a8SJordan K. Hubbard 	sgn = (n&1)&(hx>>31);	/* even n -- 0, odd n -- sign(x) */
643a8617a8SJordan K. Hubbard 	x = fabsf(x);
653a8617a8SJordan K. Hubbard 	if(ix==0||ix>=0x7f800000) 	/* if x is 0 or inf */
663a8617a8SJordan K. Hubbard 	    b = zero;
673a8617a8SJordan K. Hubbard 	else if((float)n<=x) {
683a8617a8SJordan K. Hubbard 		/* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
693a8617a8SJordan K. Hubbard 	    a = __ieee754_j0f(x);
703a8617a8SJordan K. Hubbard 	    b = __ieee754_j1f(x);
713a8617a8SJordan K. Hubbard 	    for(i=1;i<n;i++){
723a8617a8SJordan K. Hubbard 		temp = b;
733a8617a8SJordan K. Hubbard 		b = b*((float)(i+i)/x) - a; /* avoid underflow */
743a8617a8SJordan K. Hubbard 		a = temp;
753a8617a8SJordan K. Hubbard 	    }
763a8617a8SJordan K. Hubbard 	} else {
773a8617a8SJordan K. Hubbard 	    if(ix<0x30800000) {	/* x < 2**-29 */
783a8617a8SJordan K. Hubbard     /* x is tiny, return the first Taylor expansion of J(n,x)
793a8617a8SJordan K. Hubbard      * J(n,x) = 1/n!*(x/2)^n  - ...
803a8617a8SJordan K. Hubbard      */
813a8617a8SJordan K. Hubbard 		if(n>33)	/* underflow */
823a8617a8SJordan K. Hubbard 		    b = zero;
833a8617a8SJordan K. Hubbard 		else {
843a8617a8SJordan K. Hubbard 		    temp = x*(float)0.5; b = temp;
853a8617a8SJordan K. Hubbard 		    for (a=one,i=2;i<=n;i++) {
863a8617a8SJordan K. Hubbard 			a *= (float)i;		/* a = n! */
873a8617a8SJordan K. Hubbard 			b *= temp;		/* b = (x/2)^n */
883a8617a8SJordan K. Hubbard 		    }
893a8617a8SJordan K. Hubbard 		    b = b/a;
903a8617a8SJordan K. Hubbard 		}
913a8617a8SJordan K. Hubbard 	    } else {
923a8617a8SJordan K. Hubbard 		/* use backward recurrence */
933a8617a8SJordan K. Hubbard 		/* 			x      x^2      x^2
943a8617a8SJordan K. Hubbard 		 *  J(n,x)/J(n-1,x) =  ----   ------   ------   .....
953a8617a8SJordan K. Hubbard 		 *			2n  - 2(n+1) - 2(n+2)
963a8617a8SJordan K. Hubbard 		 *
973a8617a8SJordan K. Hubbard 		 * 			1      1        1
983a8617a8SJordan K. Hubbard 		 *  (for large x)   =  ----  ------   ------   .....
993a8617a8SJordan K. Hubbard 		 *			2n   2(n+1)   2(n+2)
1003a8617a8SJordan K. Hubbard 		 *			-- - ------ - ------ -
1013a8617a8SJordan K. Hubbard 		 *			 x     x         x
1023a8617a8SJordan K. Hubbard 		 *
1033a8617a8SJordan K. Hubbard 		 * Let w = 2n/x and h=2/x, then the above quotient
1043a8617a8SJordan K. Hubbard 		 * is equal to the continued fraction:
1053a8617a8SJordan K. Hubbard 		 *		    1
1063a8617a8SJordan K. Hubbard 		 *	= -----------------------
1073a8617a8SJordan K. Hubbard 		 *		       1
1083a8617a8SJordan K. Hubbard 		 *	   w - -----------------
1093a8617a8SJordan K. Hubbard 		 *			  1
1103a8617a8SJordan K. Hubbard 		 * 	        w+h - ---------
1113a8617a8SJordan K. Hubbard 		 *		       w+2h - ...
1123a8617a8SJordan K. Hubbard 		 *
1133a8617a8SJordan K. Hubbard 		 * To determine how many terms needed, let
1143a8617a8SJordan K. Hubbard 		 * Q(0) = w, Q(1) = w(w+h) - 1,
1153a8617a8SJordan K. Hubbard 		 * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
1163a8617a8SJordan K. Hubbard 		 * When Q(k) > 1e4	good for single
1173a8617a8SJordan K. Hubbard 		 * When Q(k) > 1e9	good for double
1183a8617a8SJordan K. Hubbard 		 * When Q(k) > 1e17	good for quadruple
1193a8617a8SJordan K. Hubbard 		 */
1203a8617a8SJordan K. Hubbard 	    /* determine k */
1213a8617a8SJordan K. Hubbard 		float t,v;
1223a8617a8SJordan K. Hubbard 		float q0,q1,h,tmp; int32_t k,m;
1233a8617a8SJordan K. Hubbard 		w  = (n+n)/(float)x; h = (float)2.0/(float)x;
1243a8617a8SJordan K. Hubbard 		q0 = w;  z = w+h; q1 = w*z - (float)1.0; k=1;
1253a8617a8SJordan K. Hubbard 		while(q1<(float)1.0e9) {
1263a8617a8SJordan K. Hubbard 			k += 1; z += h;
1273a8617a8SJordan K. Hubbard 			tmp = z*q1 - q0;
1283a8617a8SJordan K. Hubbard 			q0 = q1;
1293a8617a8SJordan K. Hubbard 			q1 = tmp;
1303a8617a8SJordan K. Hubbard 		}
1313a8617a8SJordan K. Hubbard 		m = n+n;
1323a8617a8SJordan K. Hubbard 		for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
1333a8617a8SJordan K. Hubbard 		a = t;
1343a8617a8SJordan K. Hubbard 		b = one;
1353a8617a8SJordan K. Hubbard 		/*  estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
1363a8617a8SJordan K. Hubbard 		 *  Hence, if n*(log(2n/x)) > ...
1373a8617a8SJordan K. Hubbard 		 *  single 8.8722839355e+01
1383a8617a8SJordan K. Hubbard 		 *  double 7.09782712893383973096e+02
1393a8617a8SJordan K. Hubbard 		 *  long double 1.1356523406294143949491931077970765006170e+04
1403a8617a8SJordan K. Hubbard 		 *  then recurrent value may overflow and the result is
1413a8617a8SJordan K. Hubbard 		 *  likely underflow to zero
1423a8617a8SJordan K. Hubbard 		 */
1433a8617a8SJordan K. Hubbard 		tmp = n;
1443a8617a8SJordan K. Hubbard 		v = two/x;
1453a8617a8SJordan K. Hubbard 		tmp = tmp*__ieee754_logf(fabsf(v*tmp));
1463a8617a8SJordan K. Hubbard 		if(tmp<(float)8.8721679688e+01) {
1473a8617a8SJordan K. Hubbard 	    	    for(i=n-1,di=(float)(i+i);i>0;i--){
1483a8617a8SJordan K. Hubbard 		        temp = b;
1493a8617a8SJordan K. Hubbard 			b *= di;
1503a8617a8SJordan K. Hubbard 			b  = b/x - a;
1513a8617a8SJordan K. Hubbard 		        a = temp;
1523a8617a8SJordan K. Hubbard 			di -= two;
1533a8617a8SJordan K. Hubbard 	     	    }
1543a8617a8SJordan K. Hubbard 		} else {
1553a8617a8SJordan K. Hubbard 	    	    for(i=n-1,di=(float)(i+i);i>0;i--){
1563a8617a8SJordan K. Hubbard 		        temp = b;
1573a8617a8SJordan K. Hubbard 			b *= di;
1583a8617a8SJordan K. Hubbard 			b  = b/x - a;
1593a8617a8SJordan K. Hubbard 		        a = temp;
1603a8617a8SJordan K. Hubbard 			di -= two;
1613a8617a8SJordan K. Hubbard 		    /* scale b to avoid spurious overflow */
1623a8617a8SJordan K. Hubbard 			if(b>(float)1e10) {
1633a8617a8SJordan K. Hubbard 			    a /= b;
1643a8617a8SJordan K. Hubbard 			    t /= b;
1653a8617a8SJordan K. Hubbard 			    b  = one;
1663a8617a8SJordan K. Hubbard 			}
1673a8617a8SJordan K. Hubbard 	     	    }
1683a8617a8SJordan K. Hubbard 		}
1693a8617a8SJordan K. Hubbard 	    	b = (t*__ieee754_j0f(x)/b);
1703a8617a8SJordan K. Hubbard 	    }
1713a8617a8SJordan K. Hubbard 	}
1723a8617a8SJordan K. Hubbard 	if(sgn==1) return -b; else return b;
1733a8617a8SJordan K. Hubbard }
1743a8617a8SJordan K. Hubbard 
1753a8617a8SJordan K. Hubbard #ifdef __STDC__
1763a8617a8SJordan K. Hubbard 	float __ieee754_ynf(int n, float x)
1773a8617a8SJordan K. Hubbard #else
1783a8617a8SJordan K. Hubbard 	float __ieee754_ynf(n,x)
1793a8617a8SJordan K. Hubbard 	int n; float x;
1803a8617a8SJordan K. Hubbard #endif
1813a8617a8SJordan K. Hubbard {
1823a8617a8SJordan K. Hubbard 	int32_t i,hx,ix,ib;
1833a8617a8SJordan K. Hubbard 	int32_t sign;
1843a8617a8SJordan K. Hubbard 	float a, b, temp;
1853a8617a8SJordan K. Hubbard 
1863a8617a8SJordan K. Hubbard 	GET_FLOAT_WORD(hx,x);
1873a8617a8SJordan K. Hubbard 	ix = 0x7fffffff&hx;
1883a8617a8SJordan K. Hubbard     /* if Y(n,NaN) is NaN */
1893a8617a8SJordan K. Hubbard 	if(ix>0x7f800000) return x+x;
1903a8617a8SJordan K. Hubbard 	if(ix==0) return -one/zero;
1913a8617a8SJordan K. Hubbard 	if(hx<0) return zero/zero;
1923a8617a8SJordan K. Hubbard 	sign = 1;
1933a8617a8SJordan K. Hubbard 	if(n<0){
1943a8617a8SJordan K. Hubbard 		n = -n;
1953a8617a8SJordan K. Hubbard 		sign = 1 - ((n&1)<<2);
1963a8617a8SJordan K. Hubbard 	}
1973a8617a8SJordan K. Hubbard 	if(n==0) return(__ieee754_y0f(x));
1983a8617a8SJordan K. Hubbard 	if(n==1) return(sign*__ieee754_y1f(x));
1993a8617a8SJordan K. Hubbard 	if(ix==0x7f800000) return zero;
2003a8617a8SJordan K. Hubbard 
2013a8617a8SJordan K. Hubbard 	a = __ieee754_y0f(x);
2023a8617a8SJordan K. Hubbard 	b = __ieee754_y1f(x);
2033a8617a8SJordan K. Hubbard 	/* quit if b is -inf */
2043a8617a8SJordan K. Hubbard 	GET_FLOAT_WORD(ib,b);
2053a8617a8SJordan K. Hubbard 	for(i=1;i<n&&ib!=0xff800000;i++){
2063a8617a8SJordan K. Hubbard 	    temp = b;
2073a8617a8SJordan K. Hubbard 	    b = ((float)(i+i)/x)*b - a;
2083a8617a8SJordan K. Hubbard 	    GET_FLOAT_WORD(ib,b);
2093a8617a8SJordan K. Hubbard 	    a = temp;
2103a8617a8SJordan K. Hubbard 	}
2113a8617a8SJordan K. Hubbard 	if(sign>0) return b; else return -b;
2123a8617a8SJordan K. Hubbard }
213