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