1*34123Sbostic /* 224581Szliu * Copyright (c) 1985 Regents of the University of California. 3*34123Sbostic * All rights reserved. 4*34123Sbostic * 5*34123Sbostic * Redistribution and use in source and binary forms are permitted 6*34123Sbostic * provided that this notice is preserved and that due credit is given 7*34123Sbostic * to the University of California at Berkeley. The name of the University 8*34123Sbostic * may not be used to endorse or promote products derived from this 9*34123Sbostic * software without specific prior written permission. This software 10*34123Sbostic * is provided ``as is'' without express or implied warranty. 11*34123Sbostic * 12*34123Sbostic * All recipients should regard themselves as participants in an ongoing 13*34123Sbostic * research project and hence should feel obligated to report their 14*34123Sbostic * experiences (good or bad) with these elementary function codes, using 15*34123Sbostic * the sendbug(8) program, to the authors. 1624581Szliu */ 1724581Szliu 1824581Szliu #ifndef lint 19*34123Sbostic static char sccsid[] = "@(#)support.c 5.2 (Berkeley) 04/29/88"; 20*34123Sbostic #endif /* not lint */ 2124581Szliu 2224581Szliu /* 2331828Szliu * Some IEEE standard 754 recommended functions and remainder and sqrt for 2424581Szliu * supporting the C elementary functions. 2524581Szliu ****************************************************************************** 2624581Szliu * WARNING: 2724581Szliu * These codes are developed (in double) to support the C elementary 2824581Szliu * functions temporarily. They are not universal, and some of them are very 2924581Szliu * slow (in particular, drem and sqrt is extremely inefficient). Each 3024581Szliu * computer system should have its implementation of these functions using 3124581Szliu * its own assembler. 3224581Szliu ****************************************************************************** 3324581Szliu * 3431828Szliu * IEEE 754 required operations: 3524581Szliu * drem(x,p) 3624581Szliu * returns x REM y = x - [x/y]*y , where [x/y] is the integer 3724581Szliu * nearest x/y; in half way case, choose the even one. 3824581Szliu * sqrt(x) 3924581Szliu * returns the square root of x correctly rounded according to 4024581Szliu * the rounding mod. 4124581Szliu * 4231828Szliu * IEEE 754 recommended functions: 4324581Szliu * (a) copysign(x,y) 4424581Szliu * returns x with the sign of y. 4524581Szliu * (b) scalb(x,N) 4624581Szliu * returns x * (2**N), for integer values N. 4724581Szliu * (c) logb(x) 4824581Szliu * returns the unbiased exponent of x, a signed integer in 4924581Szliu * double precision, except that logb(0) is -INF, logb(INF) 5024581Szliu * is +INF, and logb(NAN) is that NAN. 5124581Szliu * (d) finite(x) 5224581Szliu * returns the value TRUE if -INF < x < +INF and returns 5324581Szliu * FALSE otherwise. 5424581Szliu * 5524581Szliu * 5624581Szliu * CODED IN C BY K.C. NG, 11/25/84; 5724581Szliu * REVISED BY K.C. NG on 1/22/85, 2/13/85, 3/24/85. 5824581Szliu */ 5924581Szliu 6024581Szliu 6131856Szliu #if defined(vax)||defined(tahoe) /* VAX D format */ 6231828Szliu #include <errno.h> 6324581Szliu static unsigned short msign=0x7fff , mexp =0x7f80 ; 6424581Szliu static short prep1=57, gap=7, bias=129 ; 6524581Szliu static double novf=1.7E38, nunf=3.0E-39, zero=0.0 ; 6631856Szliu #else /* defined(vax)||defined(tahoe) */ 6724581Szliu static unsigned short msign=0x7fff, mexp =0x7ff0 ; 6824581Szliu static short prep1=54, gap=4, bias=1023 ; 6924581Szliu static double novf=1.7E308, nunf=3.0E-308,zero=0.0; 7031856Szliu #endif /* defined(vax)||defined(tahoe) */ 7124581Szliu 7224581Szliu double scalb(x,N) 7324581Szliu double x; int N; 7424581Szliu { 7524581Szliu int k; 7624581Szliu double scalb(); 7724581Szliu 7831856Szliu #ifdef national 7924581Szliu unsigned short *px=(unsigned short *) &x + 3; 8031856Szliu #else /* national */ 8124581Szliu unsigned short *px=(unsigned short *) &x; 8231856Szliu #endif /* national */ 8324581Szliu 8424581Szliu if( x == zero ) return(x); 8524581Szliu 8631856Szliu #if defined(vax)||defined(tahoe) 8724581Szliu if( (k= *px & mexp ) != ~msign ) { 8831828Szliu if (N < -260) 8931828Szliu return(nunf*nunf); 9031828Szliu else if (N > 260) { 9131828Szliu extern double infnan(),copysign(); 9231828Szliu return(copysign(infnan(ERANGE),x)); 9331828Szliu } 9431856Szliu #else /* defined(vax)||defined(tahoe) */ 9524581Szliu if( (k= *px & mexp ) != mexp ) { 9624581Szliu if( N<-2100) return(nunf*nunf); else if(N>2100) return(novf+novf); 9724581Szliu if( k == 0 ) { 9824581Szliu x *= scalb(1.0,(int)prep1); N -= prep1; return(scalb(x,N));} 9931856Szliu #endif /* defined(vax)||defined(tahoe) */ 10024581Szliu 10124581Szliu if((k = (k>>gap)+ N) > 0 ) 10224581Szliu if( k < (mexp>>gap) ) *px = (*px&~mexp) | (k<<gap); 10324581Szliu else x=novf+novf; /* overflow */ 10424581Szliu else 10524581Szliu if( k > -prep1 ) 10624581Szliu /* gradual underflow */ 10724581Szliu {*px=(*px&~mexp)|(short)(1<<gap); x *= scalb(1.0,k-1);} 10824581Szliu else 10924581Szliu return(nunf*nunf); 11024581Szliu } 11124581Szliu return(x); 11224581Szliu } 11324581Szliu 11424581Szliu 11524581Szliu double copysign(x,y) 11624581Szliu double x,y; 11724581Szliu { 11831856Szliu #ifdef national 11924581Szliu unsigned short *px=(unsigned short *) &x+3, 12024581Szliu *py=(unsigned short *) &y+3; 12131856Szliu #else /* national */ 12224581Szliu unsigned short *px=(unsigned short *) &x, 12324581Szliu *py=(unsigned short *) &y; 12431856Szliu #endif /* national */ 12524581Szliu 12631856Szliu #if defined(vax)||defined(tahoe) 12724581Szliu if ( (*px & mexp) == 0 ) return(x); 12831856Szliu #endif /* defined(vax)||defined(tahoe) */ 12924581Szliu 13024581Szliu *px = ( *px & msign ) | ( *py & ~msign ); 13124581Szliu return(x); 13224581Szliu } 13324581Szliu 13424581Szliu double logb(x) 13524581Szliu double x; 13624581Szliu { 13724581Szliu 13831856Szliu #ifdef national 13924581Szliu short *px=(short *) &x+3, k; 14031856Szliu #else /* national */ 14124581Szliu short *px=(short *) &x, k; 14231856Szliu #endif /* national */ 14324581Szliu 14431856Szliu #if defined(vax)||defined(tahoe) 14527449Szliu return (int)(((*px&mexp)>>gap)-bias); 14631856Szliu #else /* defined(vax)||defined(tahoe) */ 14724581Szliu if( (k= *px & mexp ) != mexp ) 14824581Szliu if ( k != 0 ) 14924581Szliu return ( (k>>gap) - bias ); 15024581Szliu else if( x != zero) 15124581Szliu return ( -1022.0 ); 15224581Szliu else 15324581Szliu return(-(1.0/zero)); 15424581Szliu else if(x != x) 15524581Szliu return(x); 15624581Szliu else 15724581Szliu {*px &= msign; return(x);} 15831856Szliu #endif /* defined(vax)||defined(tahoe) */ 15924581Szliu } 16024581Szliu 16124581Szliu finite(x) 16224581Szliu double x; 16324581Szliu { 16431856Szliu #if defined(vax)||defined(tahoe) 16531828Szliu return(1); 16631856Szliu #else /* defined(vax)||defined(tahoe) */ 16731856Szliu #ifdef national 16824581Szliu return( (*((short *) &x+3 ) & mexp ) != mexp ); 16931856Szliu #else /* national */ 17024581Szliu return( (*((short *) &x ) & mexp ) != mexp ); 17131856Szliu #endif /* national */ 17231856Szliu #endif /* defined(vax)||defined(tahoe) */ 17324581Szliu } 17424581Szliu 17524581Szliu double drem(x,p) 17624581Szliu double x,p; 17724581Szliu { 17824581Szliu short sign; 17924581Szliu double hp,dp,tmp,drem(),scalb(); 18024581Szliu unsigned short k; 18131856Szliu #ifdef national 18224581Szliu unsigned short 18324581Szliu *px=(unsigned short *) &x +3, 18424581Szliu *pp=(unsigned short *) &p +3, 18524581Szliu *pd=(unsigned short *) &dp +3, 18624581Szliu *pt=(unsigned short *) &tmp+3; 18731856Szliu #else /* national */ 18824581Szliu unsigned short 18924581Szliu *px=(unsigned short *) &x , 19024581Szliu *pp=(unsigned short *) &p , 19124581Szliu *pd=(unsigned short *) &dp , 19224581Szliu *pt=(unsigned short *) &tmp; 19331856Szliu #endif /* national */ 19424581Szliu 19524581Szliu *pp &= msign ; 19624581Szliu 19731856Szliu #if defined(vax)||defined(tahoe) 19831828Szliu if( ( *px & mexp ) == ~msign ) /* is x a reserved operand? */ 19931856Szliu #else /* defined(vax)||defined(tahoe) */ 20031827Szliu if( ( *px & mexp ) == mexp ) 20131856Szliu #endif /* defined(vax)||defined(tahoe) */ 20231827Szliu return (x-p)-(x-p); /* create nan if x is inf */ 20331828Szliu if (p == zero) { 20431856Szliu #if defined(vax)||defined(tahoe) 20531828Szliu extern double infnan(); 20631828Szliu return(infnan(EDOM)); 20731856Szliu #else /* defined(vax)||defined(tahoe) */ 20831828Szliu return zero/zero; 20931856Szliu #endif /* defined(vax)||defined(tahoe) */ 21031828Szliu } 21131828Szliu 21231856Szliu #if defined(vax)||defined(tahoe) 21331828Szliu if( ( *pp & mexp ) == ~msign ) /* is p a reserved operand? */ 21431856Szliu #else /* defined(vax)||defined(tahoe) */ 21531827Szliu if( ( *pp & mexp ) == mexp ) 21631856Szliu #endif /* defined(vax)||defined(tahoe) */ 21731827Szliu { if (p != p) return p; else return x;} 21824581Szliu 21924581Szliu else if ( ((*pp & mexp)>>gap) <= 1 ) 22024581Szliu /* subnormal p, or almost subnormal p */ 22124581Szliu { double b; b=scalb(1.0,(int)prep1); 22224581Szliu p *= b; x = drem(x,p); x *= b; return(drem(x,p)/b);} 22324581Szliu else if ( p >= novf/2) 22424581Szliu { p /= 2 ; x /= 2; return(drem(x,p)*2);} 22524581Szliu else 22624581Szliu { 22724581Szliu dp=p+p; hp=p/2; 22824581Szliu sign= *px & ~msign ; 22924581Szliu *px &= msign ; 23024581Szliu while ( x > dp ) 23124581Szliu { 23224581Szliu k=(*px & mexp) - (*pd & mexp) ; 23324581Szliu tmp = dp ; 23424581Szliu *pt += k ; 23524581Szliu 23631856Szliu #if defined(vax)||defined(tahoe) 23724581Szliu if( x < tmp ) *pt -= 128 ; 23831856Szliu #else /* defined(vax)||defined(tahoe) */ 23924581Szliu if( x < tmp ) *pt -= 16 ; 24031856Szliu #endif /* defined(vax)||defined(tahoe) */ 24124581Szliu 24224581Szliu x -= tmp ; 24324581Szliu } 24424581Szliu if ( x > hp ) 24524581Szliu { x -= p ; if ( x >= hp ) x -= p ; } 24624581Szliu 24731856Szliu #if defined(vax)||defined(tahoe) 24831825Szliu if (x) 24931856Szliu #endif /* defined(vax)||defined(tahoe) */ 25031825Szliu *px ^= sign; 25124581Szliu return( x); 25224581Szliu 25324581Szliu } 25424581Szliu } 25524581Szliu double sqrt(x) 25624581Szliu double x; 25724581Szliu { 25824581Szliu double q,s,b,r; 25924581Szliu double logb(),scalb(); 26024581Szliu double t,zero=0.0; 26124581Szliu int m,n,i,finite(); 26231856Szliu #if defined(vax)||defined(tahoe) 26324581Szliu int k=54; 26431856Szliu #else /* defined(vax)||defined(tahoe) */ 26524581Szliu int k=51; 26631856Szliu #endif /* defined(vax)||defined(tahoe) */ 26724581Szliu 26824581Szliu /* sqrt(NaN) is NaN, sqrt(+-0) = +-0 */ 26924581Szliu if(x!=x||x==zero) return(x); 27024581Szliu 27124581Szliu /* sqrt(negative) is invalid */ 27231828Szliu if(x<zero) { 27331856Szliu #if defined(vax)||defined(tahoe) 27431828Szliu extern double infnan(); 27531828Szliu return (infnan(EDOM)); /* NaN */ 27631856Szliu #else /* defined(vax)||defined(tahoe) */ 27731828Szliu return(zero/zero); 27831856Szliu #endif /* defined(vax)||defined(tahoe) */ 27931828Szliu } 28024581Szliu 28124581Szliu /* sqrt(INF) is INF */ 28224581Szliu if(!finite(x)) return(x); 28324581Szliu 28424581Szliu /* scale x to [1,4) */ 28524581Szliu n=logb(x); 28624581Szliu x=scalb(x,-n); 28724581Szliu if((m=logb(x))!=0) x=scalb(x,-m); /* subnormal number */ 28824581Szliu m += n; 28924581Szliu n = m/2; 29024581Szliu if((n+n)!=m) {x *= 2; m -=1; n=m/2;} 29124581Szliu 29224581Szliu /* generate sqrt(x) bit by bit (accumulating in q) */ 29324581Szliu q=1.0; s=4.0; x -= 1.0; r=1; 29424581Szliu for(i=1;i<=k;i++) { 29524581Szliu t=s+1; x *= 4; r /= 2; 29624581Szliu if(t<=x) { 29724581Szliu s=t+t+2, x -= t; q += r;} 29824581Szliu else 29924581Szliu s *= 2; 30024581Szliu } 30124581Szliu 30224581Szliu /* generate the last bit and determine the final rounding */ 30324581Szliu r/=2; x *= 4; 30424581Szliu if(x==zero) goto end; 100+r; /* trigger inexact flag */ 30524581Szliu if(s<x) { 30624581Szliu q+=r; x -=s; s += 2; s *= 2; x *= 4; 30724581Szliu t = (x-s)-5; 30824581Szliu b=1.0+3*r/4; if(b==1.0) goto end; /* b==1 : Round-to-zero */ 30924581Szliu b=1.0+r/4; if(b>1.0) t=1; /* b>1 : Round-to-(+INF) */ 31024581Szliu if(t>=0) q+=r; } /* else: Round-to-nearest */ 31124581Szliu else { 31224581Szliu s *= 2; x *= 4; 31324581Szliu t = (x-s)-1; 31424581Szliu b=1.0+3*r/4; if(b==1.0) goto end; 31524581Szliu b=1.0+r/4; if(b>1.0) t=1; 31624581Szliu if(t>=0) q+=r; } 31724581Szliu 31824581Szliu end: return(scalb(q,n)); 31924581Szliu } 32024581Szliu 32124581Szliu #if 0 32224581Szliu /* DREM(X,Y) 32324581Szliu * RETURN X REM Y =X-N*Y, N=[X/Y] ROUNDED (ROUNDED TO EVEN IN THE HALF WAY CASE) 32424581Szliu * DOUBLE PRECISION (VAX D format 56 bits, IEEE DOUBLE 53 BITS) 32524581Szliu * INTENDED FOR ASSEMBLY LANGUAGE 32624581Szliu * CODED IN C BY K.C. NG, 3/23/85, 4/8/85. 32724581Szliu * 32824581Szliu * Warning: this code should not get compiled in unless ALL of 32924581Szliu * the following machine-dependent routines are supplied. 33024581Szliu * 33124581Szliu * Required machine dependent functions (not on a VAX): 33224581Szliu * swapINX(i): save inexact flag and reset it to "i" 33324581Szliu * swapENI(e): save inexact enable and reset it to "e" 33424581Szliu */ 33524581Szliu 33624581Szliu double drem(x,y) 33724581Szliu double x,y; 33824581Szliu { 33924581Szliu 34031856Szliu #ifdef national /* order of words in floating point number */ 34124581Szliu static n0=3,n1=2,n2=1,n3=0; 34231789Szliu #else /* VAX, SUN, ZILOG, TAHOE */ 34324581Szliu static n0=0,n1=1,n2=2,n3=3; 34424581Szliu #endif 34524581Szliu 34624581Szliu static unsigned short mexp =0x7ff0, m25 =0x0190, m57 =0x0390; 34724581Szliu static double zero=0.0; 34824581Szliu double hy,y1,t,t1; 34924581Szliu short k; 35024581Szliu long n; 35124581Szliu int i,e; 35224581Szliu unsigned short xexp,yexp, *px =(unsigned short *) &x , 35324581Szliu nx,nf, *py =(unsigned short *) &y , 35424581Szliu sign, *pt =(unsigned short *) &t , 35524581Szliu *pt1 =(unsigned short *) &t1 ; 35624581Szliu 35724581Szliu xexp = px[n0] & mexp ; /* exponent of x */ 35824581Szliu yexp = py[n0] & mexp ; /* exponent of y */ 35924581Szliu sign = px[n0] &0x8000; /* sign of x */ 36024581Szliu 36124581Szliu /* return NaN if x is NaN, or y is NaN, or x is INF, or y is zero */ 36224581Szliu if(x!=x) return(x); if(y!=y) return(y); /* x or y is NaN */ 36324581Szliu if( xexp == mexp ) return(zero/zero); /* x is INF */ 36424581Szliu if(y==zero) return(y/y); 36524581Szliu 36624581Szliu /* save the inexact flag and inexact enable in i and e respectively 36724581Szliu * and reset them to zero 36824581Szliu */ 36924581Szliu i=swapINX(0); e=swapENI(0); 37024581Szliu 37124581Szliu /* subnormal number */ 37224581Szliu nx=0; 37324581Szliu if(yexp==0) {t=1.0,pt[n0]+=m57; y*=t; nx=m57;} 37424581Szliu 37524581Szliu /* if y is tiny (biased exponent <= 57), scale up y to y*2**57 */ 37624581Szliu if( yexp <= m57 ) {py[n0]+=m57; nx+=m57; yexp+=m57;} 37724581Szliu 37824581Szliu nf=nx; 37924581Szliu py[n0] &= 0x7fff; 38024581Szliu px[n0] &= 0x7fff; 38124581Szliu 38224581Szliu /* mask off the least significant 27 bits of y */ 38324581Szliu t=y; pt[n3]=0; pt[n2]&=0xf800; y1=t; 38424581Szliu 38524581Szliu /* LOOP: argument reduction on x whenever x > y */ 38624581Szliu loop: 38724581Szliu while ( x > y ) 38824581Szliu { 38924581Szliu t=y; 39024581Szliu t1=y1; 39124581Szliu xexp=px[n0]&mexp; /* exponent of x */ 39224581Szliu k=xexp-yexp-m25; 39324581Szliu if(k>0) /* if x/y >= 2**26, scale up y so that x/y < 2**26 */ 39424581Szliu {pt[n0]+=k;pt1[n0]+=k;} 39524581Szliu n=x/t; x=(x-n*t1)-n*(t-t1); 39624581Szliu } 39724581Szliu /* end while (x > y) */ 39824581Szliu 39924581Szliu if(nx!=0) {t=1.0; pt[n0]+=nx; x*=t; nx=0; goto loop;} 40024581Szliu 40124581Szliu /* final adjustment */ 40224581Szliu 40324581Szliu hy=y/2.0; 40424581Szliu if(x>hy||((x==hy)&&n%2==1)) x-=y; 40524581Szliu px[n0] ^= sign; 40624581Szliu if(nf!=0) { t=1.0; pt[n0]-=nf; x*=t;} 40724581Szliu 40824581Szliu /* restore inexact flag and inexact enable */ 40924581Szliu swapINX(i); swapENI(e); 41024581Szliu 41124581Szliu return(x); 41224581Szliu } 41324581Szliu #endif 41424581Szliu 41524581Szliu #if 0 41624581Szliu /* SQRT 41724581Szliu * RETURN CORRECTLY ROUNDED (ACCORDING TO THE ROUNDING MODE) SQRT 41824581Szliu * FOR IEEE DOUBLE PRECISION ONLY, INTENDED FOR ASSEMBLY LANGUAGE 41924581Szliu * CODED IN C BY K.C. NG, 3/22/85. 42024581Szliu * 42124581Szliu * Warning: this code should not get compiled in unless ALL of 42224581Szliu * the following machine-dependent routines are supplied. 42324581Szliu * 42424581Szliu * Required machine dependent functions: 42524581Szliu * swapINX(i) ...return the status of INEXACT flag and reset it to "i" 42624581Szliu * swapRM(r) ...return the current Rounding Mode and reset it to "r" 42724581Szliu * swapENI(e) ...return the status of inexact enable and reset it to "e" 42824581Szliu * addc(t) ...perform t=t+1 regarding t as a 64 bit unsigned integer 42924581Szliu * subc(t) ...perform t=t-1 regarding t as a 64 bit unsigned integer 43024581Szliu */ 43124581Szliu 43224581Szliu static unsigned long table[] = { 43324581Szliu 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, 29598, 36145, 43202, 50740, 43424581Szliu 58733, 67158, 75992, 85215, 83599, 71378, 60428, 50647, 41945, 34246, 27478, 43524581Szliu 21581, 16499, 12183, 8588, 5674, 3403, 1742, 661, 130, }; 43624581Szliu 43724581Szliu double newsqrt(x) 43824581Szliu double x; 43924581Szliu { 44024581Szliu double y,z,t,addc(),subc(),b54=134217728.*134217728.; /* b54=2**54 */ 44124581Szliu long mx,scalx,mexp=0x7ff00000; 44224581Szliu int i,j,r,e,swapINX(),swapRM(),swapENI(); 44324581Szliu unsigned long *py=(unsigned long *) &y , 44424581Szliu *pt=(unsigned long *) &t , 44524581Szliu *px=(unsigned long *) &x ; 44631856Szliu #ifdef national /* ordering of word in a floating point number */ 44724581Szliu int n0=1, n1=0; 44824581Szliu #else 44924581Szliu int n0=0, n1=1; 45024581Szliu #endif 45124581Szliu /* Rounding Mode: RN ...round-to-nearest 45224581Szliu * RZ ...round-towards 0 45324581Szliu * RP ...round-towards +INF 45424581Szliu * RM ...round-towards -INF 45524581Szliu */ 45624581Szliu int RN=0,RZ=1,RP=2,RM=3;/* machine dependent: work on a Zilog Z8070 45724581Szliu * and a National 32081 & 16081 45824581Szliu */ 45924581Szliu 46024581Szliu /* exceptions */ 46124581Szliu if(x!=x||x==0.0) return(x); /* sqrt(NaN) is NaN, sqrt(+-0) = +-0 */ 46224581Szliu if(x<0) return((x-x)/(x-x)); /* sqrt(negative) is invalid */ 46324581Szliu if((mx=px[n0]&mexp)==mexp) return(x); /* sqrt(+INF) is +INF */ 46424581Szliu 46524581Szliu /* save, reset, initialize */ 46624581Szliu e=swapENI(0); /* ...save and reset the inexact enable */ 46724581Szliu i=swapINX(0); /* ...save INEXACT flag */ 46824581Szliu r=swapRM(RN); /* ...save and reset the Rounding Mode to RN */ 46924581Szliu scalx=0; 47024581Szliu 47124581Szliu /* subnormal number, scale up x to x*2**54 */ 47224581Szliu if(mx==0) {x *= b54 ; scalx-=0x01b00000;} 47324581Szliu 47424581Szliu /* scale x to avoid intermediate over/underflow: 47524581Szliu * if (x > 2**512) x=x/2**512; if (x < 2**-512) x=x*2**512 */ 47624581Szliu if(mx>0x5ff00000) {px[n0] -= 0x20000000; scalx+= 0x10000000;} 47724581Szliu if(mx<0x1ff00000) {px[n0] += 0x20000000; scalx-= 0x10000000;} 47824581Szliu 47924581Szliu /* magic initial approximation to almost 8 sig. bits */ 48024581Szliu py[n0]=(px[n0]>>1)+0x1ff80000; 48124581Szliu py[n0]=py[n0]-table[(py[n0]>>15)&31]; 48224581Szliu 48324581Szliu /* Heron's rule once with correction to improve y to almost 18 sig. bits */ 48424581Szliu t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; 48524581Szliu 48624581Szliu /* triple to almost 56 sig. bits; now y approx. sqrt(x) to within 1 ulp */ 48724581Szliu t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; 48824581Szliu t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; 48924581Szliu 49024581Szliu /* twiddle last bit to force y correctly rounded */ 49124581Szliu swapRM(RZ); /* ...set Rounding Mode to round-toward-zero */ 49224581Szliu swapINX(0); /* ...clear INEXACT flag */ 49324581Szliu swapENI(e); /* ...restore inexact enable status */ 49424581Szliu t=x/y; /* ...chopped quotient, possibly inexact */ 49524581Szliu j=swapINX(i); /* ...read and restore inexact flag */ 49624581Szliu if(j==0) { if(t==y) goto end; else t=subc(t); } /* ...t=t-ulp */ 49724581Szliu b54+0.1; /* ..trigger inexact flag, sqrt(x) is inexact */ 49824581Szliu if(r==RN) t=addc(t); /* ...t=t+ulp */ 49924581Szliu else if(r==RP) { t=addc(t);y=addc(y);}/* ...t=t+ulp;y=y+ulp; */ 50024581Szliu y=y+t; /* ...chopped sum */ 50124581Szliu py[n0]=py[n0]-0x00100000; /* ...correctly rounded sqrt(x) */ 50224581Szliu end: py[n0]=py[n0]+scalx; /* ...scale back y */ 50324581Szliu swapRM(r); /* ...restore Rounding Mode */ 50424581Szliu return(y); 50524581Szliu } 50624581Szliu #endif 507