xref: /freebsd/lib/msun/src/e_jnf.c (revision 0dd5a5603e7a33d976f8e6015620bbc79839c609)
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 
16186f6207SSteve Kargl /*
17186f6207SSteve Kargl  * See e_jn.c for complete comments.
18186f6207SSteve Kargl  */
19186f6207SSteve Kargl 
203a8617a8SJordan K. Hubbard #include "math.h"
213a8617a8SJordan K. Hubbard #include "math_private.h"
223a8617a8SJordan K. Hubbard 
23186f6207SSteve Kargl static const volatile float vone = 1, vzero = 0;
24186f6207SSteve Kargl 
253a8617a8SJordan K. Hubbard static const float
263a8617a8SJordan K. Hubbard two   =  2.0000000000e+00, /* 0x40000000 */
273a8617a8SJordan K. Hubbard one   =  1.0000000000e+00; /* 0x3F800000 */
283a8617a8SJordan K. Hubbard 
293a8617a8SJordan K. Hubbard static const float zero  =  0.0000000000e+00;
303a8617a8SJordan K. Hubbard 
3159b19ff1SAlfred Perlstein float
jnf(int n,float x)32*99843eb8SSteve Kargl jnf(int n, float x)
333a8617a8SJordan K. Hubbard {
343a8617a8SJordan K. Hubbard 	int32_t i,hx,ix, sgn;
353a8617a8SJordan K. Hubbard 	float a, b, temp, di;
363a8617a8SJordan K. Hubbard 	float z, w;
373a8617a8SJordan K. Hubbard 
383a8617a8SJordan K. Hubbard     /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
393a8617a8SJordan K. Hubbard      * Thus, J(-n,x) = J(n,-x)
403a8617a8SJordan K. Hubbard      */
413a8617a8SJordan K. Hubbard 	GET_FLOAT_WORD(hx,x);
423a8617a8SJordan K. Hubbard 	ix = 0x7fffffff&hx;
433a8617a8SJordan K. Hubbard     /* if J(n,NaN) is NaN */
443a8617a8SJordan K. Hubbard 	if(ix>0x7f800000) return x+x;
453a8617a8SJordan K. Hubbard 	if(n<0){
463a8617a8SJordan K. Hubbard 		n = -n;
473a8617a8SJordan K. Hubbard 		x = -x;
483a8617a8SJordan K. Hubbard 		hx ^= 0x80000000;
493a8617a8SJordan K. Hubbard 	}
50*99843eb8SSteve Kargl 	if(n==0) return(j0f(x));
51*99843eb8SSteve Kargl 	if(n==1) return(j1f(x));
523a8617a8SJordan K. Hubbard 	sgn = (n&1)&(hx>>31);	/* even n -- 0, odd n -- sign(x) */
533a8617a8SJordan K. Hubbard 	x = fabsf(x);
543a8617a8SJordan K. Hubbard 	if(ix==0||ix>=0x7f800000) 	/* if x is 0 or inf */
553a8617a8SJordan K. Hubbard 	    b = zero;
563a8617a8SJordan K. Hubbard 	else if((float)n<=x) {
573a8617a8SJordan K. Hubbard 		/* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
58*99843eb8SSteve Kargl 	    a = j0f(x);
59*99843eb8SSteve Kargl 	    b = j1f(x);
603a8617a8SJordan K. Hubbard 	    for(i=1;i<n;i++){
613a8617a8SJordan K. Hubbard 		temp = b;
623a8617a8SJordan K. Hubbard 		b = b*((float)(i+i)/x) - a; /* avoid underflow */
633a8617a8SJordan K. Hubbard 		a = temp;
643a8617a8SJordan K. Hubbard 	    }
653a8617a8SJordan K. Hubbard 	} else {
663a8617a8SJordan K. Hubbard 	    if(ix<0x30800000) {	/* x < 2**-29 */
673a8617a8SJordan K. Hubbard     /* x is tiny, return the first Taylor expansion of J(n,x)
683a8617a8SJordan K. Hubbard      * J(n,x) = 1/n!*(x/2)^n  - ...
693a8617a8SJordan K. Hubbard      */
703a8617a8SJordan K. Hubbard 		if(n>33)	/* underflow */
713a8617a8SJordan K. Hubbard 		    b = zero;
723a8617a8SJordan K. Hubbard 		else {
733a8617a8SJordan K. Hubbard 		    temp = x*(float)0.5; b = temp;
743a8617a8SJordan K. Hubbard 		    for (a=one,i=2;i<=n;i++) {
753a8617a8SJordan K. Hubbard 			a *= (float)i;		/* a = n! */
763a8617a8SJordan K. Hubbard 			b *= temp;		/* b = (x/2)^n */
773a8617a8SJordan K. Hubbard 		    }
783a8617a8SJordan K. Hubbard 		    b = b/a;
793a8617a8SJordan K. Hubbard 		}
803a8617a8SJordan K. Hubbard 	    } else {
813a8617a8SJordan K. Hubbard 		/* use backward recurrence */
823a8617a8SJordan K. Hubbard 		/* 			x      x^2      x^2
833a8617a8SJordan K. Hubbard 		 *  J(n,x)/J(n-1,x) =  ----   ------   ------   .....
843a8617a8SJordan K. Hubbard 		 *			2n  - 2(n+1) - 2(n+2)
853a8617a8SJordan K. Hubbard 		 *
863a8617a8SJordan K. Hubbard 		 * 			1      1        1
873a8617a8SJordan K. Hubbard 		 *  (for large x)   =  ----  ------   ------   .....
883a8617a8SJordan K. Hubbard 		 *			2n   2(n+1)   2(n+2)
893a8617a8SJordan K. Hubbard 		 *			-- - ------ - ------ -
903a8617a8SJordan K. Hubbard 		 *			 x     x         x
913a8617a8SJordan K. Hubbard 		 *
923a8617a8SJordan K. Hubbard 		 * Let w = 2n/x and h=2/x, then the above quotient
933a8617a8SJordan K. Hubbard 		 * is equal to the continued fraction:
943a8617a8SJordan K. Hubbard 		 *		    1
953a8617a8SJordan K. Hubbard 		 *	= -----------------------
963a8617a8SJordan K. Hubbard 		 *		       1
973a8617a8SJordan K. Hubbard 		 *	   w - -----------------
983a8617a8SJordan K. Hubbard 		 *			  1
993a8617a8SJordan K. Hubbard 		 * 	        w+h - ---------
1003a8617a8SJordan K. Hubbard 		 *		       w+2h - ...
1013a8617a8SJordan K. Hubbard 		 *
1023a8617a8SJordan K. Hubbard 		 * To determine how many terms needed, let
1033a8617a8SJordan K. Hubbard 		 * Q(0) = w, Q(1) = w(w+h) - 1,
1043a8617a8SJordan K. Hubbard 		 * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
1053a8617a8SJordan K. Hubbard 		 * When Q(k) > 1e4	good for single
1063a8617a8SJordan K. Hubbard 		 * When Q(k) > 1e9	good for double
1073a8617a8SJordan K. Hubbard 		 * When Q(k) > 1e17	good for quadruple
1083a8617a8SJordan K. Hubbard 		 */
1093a8617a8SJordan K. Hubbard 	    /* determine k */
1103a8617a8SJordan K. Hubbard 		float t,v;
1113a8617a8SJordan K. Hubbard 		float q0,q1,h,tmp; int32_t k,m;
1123a8617a8SJordan K. Hubbard 		w  = (n+n)/(float)x; h = (float)2.0/(float)x;
1133a8617a8SJordan K. Hubbard 		q0 = w;  z = w+h; q1 = w*z - (float)1.0; k=1;
1143a8617a8SJordan K. Hubbard 		while(q1<(float)1.0e9) {
1153a8617a8SJordan K. Hubbard 			k += 1; z += h;
1163a8617a8SJordan K. Hubbard 			tmp = z*q1 - q0;
1173a8617a8SJordan K. Hubbard 			q0 = q1;
1183a8617a8SJordan K. Hubbard 			q1 = tmp;
1193a8617a8SJordan K. Hubbard 		}
1203a8617a8SJordan K. Hubbard 		m = n+n;
1213a8617a8SJordan K. Hubbard 		for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
1223a8617a8SJordan K. Hubbard 		a = t;
1233a8617a8SJordan K. Hubbard 		b = one;
1243a8617a8SJordan K. Hubbard 		/*  estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
1253a8617a8SJordan K. Hubbard 		 *  Hence, if n*(log(2n/x)) > ...
1263a8617a8SJordan K. Hubbard 		 *  single 8.8722839355e+01
1273a8617a8SJordan K. Hubbard 		 *  double 7.09782712893383973096e+02
1283a8617a8SJordan K. Hubbard 		 *  long double 1.1356523406294143949491931077970765006170e+04
1293a8617a8SJordan K. Hubbard 		 *  then recurrent value may overflow and the result is
1303a8617a8SJordan K. Hubbard 		 *  likely underflow to zero
1313a8617a8SJordan K. Hubbard 		 */
1323a8617a8SJordan K. Hubbard 		tmp = n;
1333a8617a8SJordan K. Hubbard 		v = two/x;
134*99843eb8SSteve Kargl 		tmp = tmp*logf(fabsf(v*tmp));
1353a8617a8SJordan K. Hubbard 		if(tmp<(float)8.8721679688e+01) {
1363a8617a8SJordan K. Hubbard 	    	    for(i=n-1,di=(float)(i+i);i>0;i--){
1373a8617a8SJordan K. Hubbard 		        temp = b;
1383a8617a8SJordan K. Hubbard 			b *= di;
1393a8617a8SJordan K. Hubbard 			b  = b/x - a;
1403a8617a8SJordan K. Hubbard 		        a = temp;
1413a8617a8SJordan K. Hubbard 			di -= two;
1423a8617a8SJordan K. Hubbard 	     	    }
1433a8617a8SJordan K. Hubbard 		} else {
1443a8617a8SJordan K. Hubbard 	    	    for(i=n-1,di=(float)(i+i);i>0;i--){
1453a8617a8SJordan K. Hubbard 		        temp = b;
1463a8617a8SJordan K. Hubbard 			b *= di;
1473a8617a8SJordan K. Hubbard 			b  = b/x - a;
1483a8617a8SJordan K. Hubbard 		        a = temp;
1493a8617a8SJordan K. Hubbard 			di -= two;
1503a8617a8SJordan K. Hubbard 		    /* scale b to avoid spurious overflow */
1513a8617a8SJordan K. Hubbard 			if(b>(float)1e10) {
1523a8617a8SJordan K. Hubbard 			    a /= b;
1533a8617a8SJordan K. Hubbard 			    t /= b;
1543a8617a8SJordan K. Hubbard 			    b  = one;
1553a8617a8SJordan K. Hubbard 			}
1563a8617a8SJordan K. Hubbard 	     	    }
1573a8617a8SJordan K. Hubbard 		}
158*99843eb8SSteve Kargl 		z = j0f(x);
159*99843eb8SSteve Kargl 		w = j1f(x);
160e61ffaeaSUlrich Spörlein 		if (fabsf(z) >= fabsf(w))
161e61ffaeaSUlrich Spörlein 		    b = (t*z/b);
162e61ffaeaSUlrich Spörlein 		else
163e61ffaeaSUlrich Spörlein 		    b = (t*w/a);
1643a8617a8SJordan K. Hubbard 	    }
1653a8617a8SJordan K. Hubbard 	}
1663a8617a8SJordan K. Hubbard 	if(sgn==1) return -b; else return b;
1673a8617a8SJordan K. Hubbard }
1683a8617a8SJordan K. Hubbard 
16959b19ff1SAlfred Perlstein float
ynf(int n,float x)170*99843eb8SSteve Kargl ynf(int n, float x)
1713a8617a8SJordan K. Hubbard {
1723a8617a8SJordan K. Hubbard 	int32_t i,hx,ix,ib;
1733a8617a8SJordan K. Hubbard 	int32_t sign;
1743a8617a8SJordan K. Hubbard 	float a, b, temp;
1753a8617a8SJordan K. Hubbard 
1763a8617a8SJordan K. Hubbard 	GET_FLOAT_WORD(hx,x);
1773a8617a8SJordan K. Hubbard 	ix = 0x7fffffff&hx;
1783a8617a8SJordan K. Hubbard 	if(ix>0x7f800000) return x+x;
179186f6207SSteve Kargl 	if(ix==0) return -one/vzero;
180186f6207SSteve Kargl 	if(hx<0) return vzero/vzero;
1813a8617a8SJordan K. Hubbard 	sign = 1;
1823a8617a8SJordan K. Hubbard 	if(n<0){
1833a8617a8SJordan K. Hubbard 		n = -n;
184b29986e0SBruce Evans 		sign = 1 - ((n&1)<<1);
1853a8617a8SJordan K. Hubbard 	}
186*99843eb8SSteve Kargl 	if(n==0) return(y0f(x));
187*99843eb8SSteve Kargl 	if(n==1) return(sign*y1f(x));
1883a8617a8SJordan K. Hubbard 	if(ix==0x7f800000) return zero;
1893a8617a8SJordan K. Hubbard 
190*99843eb8SSteve Kargl 	a = y0f(x);
191*99843eb8SSteve Kargl 	b = y1f(x);
1923a8617a8SJordan K. Hubbard 	/* quit if b is -inf */
1933a8617a8SJordan K. Hubbard 	GET_FLOAT_WORD(ib,b);
1943a8617a8SJordan K. Hubbard 	for(i=1;i<n&&ib!=0xff800000;i++){
1953a8617a8SJordan K. Hubbard 	    temp = b;
1963a8617a8SJordan K. Hubbard 	    b = ((float)(i+i)/x)*b - a;
1973a8617a8SJordan K. Hubbard 	    GET_FLOAT_WORD(ib,b);
1983a8617a8SJordan K. Hubbard 	    a = temp;
1993a8617a8SJordan K. Hubbard 	}
2003a8617a8SJordan K. Hubbard 	if(sign>0) return b; else return -b;
2013a8617a8SJordan K. Hubbard }
202