134123Sbostic /* 224581Szliu * Copyright (c) 1985 Regents of the University of California. 334123Sbostic * All rights reserved. 434123Sbostic * 5*42657Sbostic * %sccs.include.redist.c% 634123Sbostic * 734123Sbostic * All recipients should regard themselves as participants in an ongoing 834123Sbostic * research project and hence should feel obligated to report their 934123Sbostic * experiences (good or bad) with these elementary function codes, using 1034123Sbostic * the sendbug(8) program, to the authors. 1124581Szliu */ 1224581Szliu 1324581Szliu #ifndef lint 14*42657Sbostic static char sccsid[] = "@(#)support.c 5.5 (Berkeley) 06/01/90"; 1534123Sbostic #endif /* not lint */ 1624581Szliu 1724581Szliu /* 1831828Szliu * Some IEEE standard 754 recommended functions and remainder and sqrt for 1924581Szliu * supporting the C elementary functions. 2024581Szliu ****************************************************************************** 2124581Szliu * WARNING: 2224581Szliu * These codes are developed (in double) to support the C elementary 2324581Szliu * functions temporarily. They are not universal, and some of them are very 2424581Szliu * slow (in particular, drem and sqrt is extremely inefficient). Each 2524581Szliu * computer system should have its implementation of these functions using 2624581Szliu * its own assembler. 2724581Szliu ****************************************************************************** 2824581Szliu * 2931828Szliu * IEEE 754 required operations: 3024581Szliu * drem(x,p) 3124581Szliu * returns x REM y = x - [x/y]*y , where [x/y] is the integer 3224581Szliu * nearest x/y; in half way case, choose the even one. 3324581Szliu * sqrt(x) 3424581Szliu * returns the square root of x correctly rounded according to 3524581Szliu * the rounding mod. 3624581Szliu * 3731828Szliu * IEEE 754 recommended functions: 3824581Szliu * (a) copysign(x,y) 3924581Szliu * returns x with the sign of y. 4024581Szliu * (b) scalb(x,N) 4124581Szliu * returns x * (2**N), for integer values N. 4224581Szliu * (c) logb(x) 4324581Szliu * returns the unbiased exponent of x, a signed integer in 4424581Szliu * double precision, except that logb(0) is -INF, logb(INF) 4524581Szliu * is +INF, and logb(NAN) is that NAN. 4624581Szliu * (d) finite(x) 4724581Szliu * returns the value TRUE if -INF < x < +INF and returns 4824581Szliu * FALSE otherwise. 4924581Szliu * 5024581Szliu * 5124581Szliu * CODED IN C BY K.C. NG, 11/25/84; 5224581Szliu * REVISED BY K.C. NG on 1/22/85, 2/13/85, 3/24/85. 5324581Szliu */ 5424581Szliu 5535681Sbostic #include "mathimpl.h" 5624581Szliu 5731856Szliu #if defined(vax)||defined(tahoe) /* VAX D format */ 5831828Szliu #include <errno.h> 5935681Sbostic static const unsigned short msign=0x7fff , mexp =0x7f80 ; 6035681Sbostic static const short prep1=57, gap=7, bias=129 ; 6135681Sbostic static const double novf=1.7E38, nunf=3.0E-39, zero=0.0 ; 6231856Szliu #else /* defined(vax)||defined(tahoe) */ 6335681Sbostic static const unsigned short msign=0x7fff, mexp =0x7ff0 ; 6435681Sbostic static const short prep1=54, gap=4, bias=1023 ; 6535681Sbostic static const double novf=1.7E308, nunf=3.0E-308,zero=0.0; 6631856Szliu #endif /* defined(vax)||defined(tahoe) */ 6724581Szliu 6824581Szliu double scalb(x,N) 6924581Szliu double x; int N; 7024581Szliu { 7124581Szliu int k; 7224581Szliu 7331856Szliu #ifdef national 7424581Szliu unsigned short *px=(unsigned short *) &x + 3; 7531856Szliu #else /* national */ 7624581Szliu unsigned short *px=(unsigned short *) &x; 7731856Szliu #endif /* national */ 7824581Szliu 7924581Szliu if( x == zero ) return(x); 8024581Szliu 8131856Szliu #if defined(vax)||defined(tahoe) 8224581Szliu if( (k= *px & mexp ) != ~msign ) { 8331828Szliu if (N < -260) 8431828Szliu return(nunf*nunf); 8531828Szliu else if (N > 260) { 8631828Szliu return(copysign(infnan(ERANGE),x)); 8731828Szliu } 8831856Szliu #else /* defined(vax)||defined(tahoe) */ 8924581Szliu if( (k= *px & mexp ) != mexp ) { 9024581Szliu if( N<-2100) return(nunf*nunf); else if(N>2100) return(novf+novf); 9124581Szliu if( k == 0 ) { 9224581Szliu x *= scalb(1.0,(int)prep1); N -= prep1; return(scalb(x,N));} 9331856Szliu #endif /* defined(vax)||defined(tahoe) */ 9424581Szliu 9524581Szliu if((k = (k>>gap)+ N) > 0 ) 9624581Szliu if( k < (mexp>>gap) ) *px = (*px&~mexp) | (k<<gap); 9724581Szliu else x=novf+novf; /* overflow */ 9824581Szliu else 9924581Szliu if( k > -prep1 ) 10024581Szliu /* gradual underflow */ 10124581Szliu {*px=(*px&~mexp)|(short)(1<<gap); x *= scalb(1.0,k-1);} 10224581Szliu else 10324581Szliu return(nunf*nunf); 10424581Szliu } 10524581Szliu return(x); 10624581Szliu } 10724581Szliu 10824581Szliu 10924581Szliu double copysign(x,y) 11024581Szliu double x,y; 11124581Szliu { 11231856Szliu #ifdef national 11324581Szliu unsigned short *px=(unsigned short *) &x+3, 11424581Szliu *py=(unsigned short *) &y+3; 11531856Szliu #else /* national */ 11624581Szliu unsigned short *px=(unsigned short *) &x, 11724581Szliu *py=(unsigned short *) &y; 11831856Szliu #endif /* national */ 11924581Szliu 12031856Szliu #if defined(vax)||defined(tahoe) 12124581Szliu if ( (*px & mexp) == 0 ) return(x); 12231856Szliu #endif /* defined(vax)||defined(tahoe) */ 12324581Szliu 12424581Szliu *px = ( *px & msign ) | ( *py & ~msign ); 12524581Szliu return(x); 12624581Szliu } 12724581Szliu 12824581Szliu double logb(x) 12924581Szliu double x; 13024581Szliu { 13124581Szliu 13231856Szliu #ifdef national 13324581Szliu short *px=(short *) &x+3, k; 13431856Szliu #else /* national */ 13524581Szliu short *px=(short *) &x, k; 13631856Szliu #endif /* national */ 13724581Szliu 13831856Szliu #if defined(vax)||defined(tahoe) 13927449Szliu return (int)(((*px&mexp)>>gap)-bias); 14031856Szliu #else /* defined(vax)||defined(tahoe) */ 14124581Szliu if( (k= *px & mexp ) != mexp ) 14224581Szliu if ( k != 0 ) 14324581Szliu return ( (k>>gap) - bias ); 14424581Szliu else if( x != zero) 14524581Szliu return ( -1022.0 ); 14624581Szliu else 14724581Szliu return(-(1.0/zero)); 14824581Szliu else if(x != x) 14924581Szliu return(x); 15024581Szliu else 15124581Szliu {*px &= msign; return(x);} 15231856Szliu #endif /* defined(vax)||defined(tahoe) */ 15324581Szliu } 15424581Szliu 15524581Szliu finite(x) 15624581Szliu double x; 15724581Szliu { 15831856Szliu #if defined(vax)||defined(tahoe) 15931828Szliu return(1); 16031856Szliu #else /* defined(vax)||defined(tahoe) */ 16131856Szliu #ifdef national 16224581Szliu return( (*((short *) &x+3 ) & mexp ) != mexp ); 16331856Szliu #else /* national */ 16424581Szliu return( (*((short *) &x ) & mexp ) != mexp ); 16531856Szliu #endif /* national */ 16631856Szliu #endif /* defined(vax)||defined(tahoe) */ 16724581Szliu } 16824581Szliu 16924581Szliu double drem(x,p) 17024581Szliu double x,p; 17124581Szliu { 17224581Szliu short sign; 17335681Sbostic double hp,dp,tmp; 17424581Szliu unsigned short k; 17531856Szliu #ifdef national 17624581Szliu unsigned short 17724581Szliu *px=(unsigned short *) &x +3, 17824581Szliu *pp=(unsigned short *) &p +3, 17924581Szliu *pd=(unsigned short *) &dp +3, 18024581Szliu *pt=(unsigned short *) &tmp+3; 18131856Szliu #else /* national */ 18224581Szliu unsigned short 18324581Szliu *px=(unsigned short *) &x , 18424581Szliu *pp=(unsigned short *) &p , 18524581Szliu *pd=(unsigned short *) &dp , 18624581Szliu *pt=(unsigned short *) &tmp; 18731856Szliu #endif /* national */ 18824581Szliu 18924581Szliu *pp &= msign ; 19024581Szliu 19131856Szliu #if defined(vax)||defined(tahoe) 19231828Szliu if( ( *px & mexp ) == ~msign ) /* is x a reserved operand? */ 19331856Szliu #else /* defined(vax)||defined(tahoe) */ 19431827Szliu if( ( *px & mexp ) == mexp ) 19531856Szliu #endif /* defined(vax)||defined(tahoe) */ 19631827Szliu return (x-p)-(x-p); /* create nan if x is inf */ 19731828Szliu if (p == zero) { 19831856Szliu #if defined(vax)||defined(tahoe) 19931828Szliu return(infnan(EDOM)); 20031856Szliu #else /* defined(vax)||defined(tahoe) */ 20131828Szliu return zero/zero; 20231856Szliu #endif /* defined(vax)||defined(tahoe) */ 20331828Szliu } 20431828Szliu 20531856Szliu #if defined(vax)||defined(tahoe) 20631828Szliu if( ( *pp & mexp ) == ~msign ) /* is p a reserved operand? */ 20731856Szliu #else /* defined(vax)||defined(tahoe) */ 20831827Szliu if( ( *pp & mexp ) == mexp ) 20931856Szliu #endif /* defined(vax)||defined(tahoe) */ 21031827Szliu { if (p != p) return p; else return x;} 21124581Szliu 21224581Szliu else if ( ((*pp & mexp)>>gap) <= 1 ) 21324581Szliu /* subnormal p, or almost subnormal p */ 21424581Szliu { double b; b=scalb(1.0,(int)prep1); 21524581Szliu p *= b; x = drem(x,p); x *= b; return(drem(x,p)/b);} 21624581Szliu else if ( p >= novf/2) 21724581Szliu { p /= 2 ; x /= 2; return(drem(x,p)*2);} 21824581Szliu else 21924581Szliu { 22024581Szliu dp=p+p; hp=p/2; 22124581Szliu sign= *px & ~msign ; 22224581Szliu *px &= msign ; 22324581Szliu while ( x > dp ) 22424581Szliu { 22524581Szliu k=(*px & mexp) - (*pd & mexp) ; 22624581Szliu tmp = dp ; 22724581Szliu *pt += k ; 22824581Szliu 22931856Szliu #if defined(vax)||defined(tahoe) 23024581Szliu if( x < tmp ) *pt -= 128 ; 23131856Szliu #else /* defined(vax)||defined(tahoe) */ 23224581Szliu if( x < tmp ) *pt -= 16 ; 23331856Szliu #endif /* defined(vax)||defined(tahoe) */ 23424581Szliu 23524581Szliu x -= tmp ; 23624581Szliu } 23724581Szliu if ( x > hp ) 23824581Szliu { x -= p ; if ( x >= hp ) x -= p ; } 23924581Szliu 24031856Szliu #if defined(vax)||defined(tahoe) 24131825Szliu if (x) 24231856Szliu #endif /* defined(vax)||defined(tahoe) */ 24331825Szliu *px ^= sign; 24424581Szliu return( x); 24524581Szliu 24624581Szliu } 24724581Szliu } 24835681Sbostic 24935681Sbostic 25024581Szliu double sqrt(x) 25124581Szliu double x; 25224581Szliu { 25324581Szliu double q,s,b,r; 25435681Sbostic double t; 25535681Sbostic double const zero=0.0; 25635681Sbostic int m,n,i; 25731856Szliu #if defined(vax)||defined(tahoe) 25824581Szliu int k=54; 25931856Szliu #else /* defined(vax)||defined(tahoe) */ 26024581Szliu int k=51; 26131856Szliu #endif /* defined(vax)||defined(tahoe) */ 26224581Szliu 26324581Szliu /* sqrt(NaN) is NaN, sqrt(+-0) = +-0 */ 26424581Szliu if(x!=x||x==zero) return(x); 26524581Szliu 26624581Szliu /* sqrt(negative) is invalid */ 26731828Szliu if(x<zero) { 26831856Szliu #if defined(vax)||defined(tahoe) 26931828Szliu return (infnan(EDOM)); /* NaN */ 27031856Szliu #else /* defined(vax)||defined(tahoe) */ 27131828Szliu return(zero/zero); 27231856Szliu #endif /* defined(vax)||defined(tahoe) */ 27331828Szliu } 27424581Szliu 27524581Szliu /* sqrt(INF) is INF */ 27624581Szliu if(!finite(x)) return(x); 27724581Szliu 27824581Szliu /* scale x to [1,4) */ 27924581Szliu n=logb(x); 28024581Szliu x=scalb(x,-n); 28124581Szliu if((m=logb(x))!=0) x=scalb(x,-m); /* subnormal number */ 28224581Szliu m += n; 28324581Szliu n = m/2; 28424581Szliu if((n+n)!=m) {x *= 2; m -=1; n=m/2;} 28524581Szliu 28624581Szliu /* generate sqrt(x) bit by bit (accumulating in q) */ 28724581Szliu q=1.0; s=4.0; x -= 1.0; r=1; 28824581Szliu for(i=1;i<=k;i++) { 28924581Szliu t=s+1; x *= 4; r /= 2; 29024581Szliu if(t<=x) { 29124581Szliu s=t+t+2, x -= t; q += r;} 29224581Szliu else 29324581Szliu s *= 2; 29424581Szliu } 29524581Szliu 29624581Szliu /* generate the last bit and determine the final rounding */ 29724581Szliu r/=2; x *= 4; 29824581Szliu if(x==zero) goto end; 100+r; /* trigger inexact flag */ 29924581Szliu if(s<x) { 30024581Szliu q+=r; x -=s; s += 2; s *= 2; x *= 4; 30124581Szliu t = (x-s)-5; 30224581Szliu b=1.0+3*r/4; if(b==1.0) goto end; /* b==1 : Round-to-zero */ 30324581Szliu b=1.0+r/4; if(b>1.0) t=1; /* b>1 : Round-to-(+INF) */ 30424581Szliu if(t>=0) q+=r; } /* else: Round-to-nearest */ 30524581Szliu else { 30624581Szliu s *= 2; x *= 4; 30724581Szliu t = (x-s)-1; 30824581Szliu b=1.0+3*r/4; if(b==1.0) goto end; 30924581Szliu b=1.0+r/4; if(b>1.0) t=1; 31024581Szliu if(t>=0) q+=r; } 31124581Szliu 31224581Szliu end: return(scalb(q,n)); 31324581Szliu } 31424581Szliu 31524581Szliu #if 0 31624581Szliu /* DREM(X,Y) 31724581Szliu * RETURN X REM Y =X-N*Y, N=[X/Y] ROUNDED (ROUNDED TO EVEN IN THE HALF WAY CASE) 31824581Szliu * DOUBLE PRECISION (VAX D format 56 bits, IEEE DOUBLE 53 BITS) 31924581Szliu * INTENDED FOR ASSEMBLY LANGUAGE 32024581Szliu * CODED IN C BY K.C. NG, 3/23/85, 4/8/85. 32124581Szliu * 32224581Szliu * Warning: this code should not get compiled in unless ALL of 32324581Szliu * the following machine-dependent routines are supplied. 32424581Szliu * 32524581Szliu * Required machine dependent functions (not on a VAX): 32624581Szliu * swapINX(i): save inexact flag and reset it to "i" 32724581Szliu * swapENI(e): save inexact enable and reset it to "e" 32824581Szliu */ 32924581Szliu 33024581Szliu double drem(x,y) 33124581Szliu double x,y; 33224581Szliu { 33324581Szliu 33431856Szliu #ifdef national /* order of words in floating point number */ 33535681Sbostic static const n0=3,n1=2,n2=1,n3=0; 33631789Szliu #else /* VAX, SUN, ZILOG, TAHOE */ 33735681Sbostic static const n0=0,n1=1,n2=2,n3=3; 33824581Szliu #endif 33924581Szliu 34035681Sbostic static const unsigned short mexp =0x7ff0, m25 =0x0190, m57 =0x0390; 34135681Sbostic static const double zero=0.0; 34224581Szliu double hy,y1,t,t1; 34324581Szliu short k; 34424581Szliu long n; 34524581Szliu int i,e; 34624581Szliu unsigned short xexp,yexp, *px =(unsigned short *) &x , 34724581Szliu nx,nf, *py =(unsigned short *) &y , 34824581Szliu sign, *pt =(unsigned short *) &t , 34924581Szliu *pt1 =(unsigned short *) &t1 ; 35024581Szliu 35124581Szliu xexp = px[n0] & mexp ; /* exponent of x */ 35224581Szliu yexp = py[n0] & mexp ; /* exponent of y */ 35324581Szliu sign = px[n0] &0x8000; /* sign of x */ 35424581Szliu 35524581Szliu /* return NaN if x is NaN, or y is NaN, or x is INF, or y is zero */ 35624581Szliu if(x!=x) return(x); if(y!=y) return(y); /* x or y is NaN */ 35724581Szliu if( xexp == mexp ) return(zero/zero); /* x is INF */ 35824581Szliu if(y==zero) return(y/y); 35924581Szliu 36024581Szliu /* save the inexact flag and inexact enable in i and e respectively 36124581Szliu * and reset them to zero 36224581Szliu */ 36324581Szliu i=swapINX(0); e=swapENI(0); 36424581Szliu 36524581Szliu /* subnormal number */ 36624581Szliu nx=0; 36724581Szliu if(yexp==0) {t=1.0,pt[n0]+=m57; y*=t; nx=m57;} 36824581Szliu 36924581Szliu /* if y is tiny (biased exponent <= 57), scale up y to y*2**57 */ 37024581Szliu if( yexp <= m57 ) {py[n0]+=m57; nx+=m57; yexp+=m57;} 37124581Szliu 37224581Szliu nf=nx; 37324581Szliu py[n0] &= 0x7fff; 37424581Szliu px[n0] &= 0x7fff; 37524581Szliu 37624581Szliu /* mask off the least significant 27 bits of y */ 37724581Szliu t=y; pt[n3]=0; pt[n2]&=0xf800; y1=t; 37824581Szliu 37924581Szliu /* LOOP: argument reduction on x whenever x > y */ 38024581Szliu loop: 38124581Szliu while ( x > y ) 38224581Szliu { 38324581Szliu t=y; 38424581Szliu t1=y1; 38524581Szliu xexp=px[n0]&mexp; /* exponent of x */ 38624581Szliu k=xexp-yexp-m25; 38724581Szliu if(k>0) /* if x/y >= 2**26, scale up y so that x/y < 2**26 */ 38824581Szliu {pt[n0]+=k;pt1[n0]+=k;} 38924581Szliu n=x/t; x=(x-n*t1)-n*(t-t1); 39024581Szliu } 39124581Szliu /* end while (x > y) */ 39224581Szliu 39324581Szliu if(nx!=0) {t=1.0; pt[n0]+=nx; x*=t; nx=0; goto loop;} 39424581Szliu 39524581Szliu /* final adjustment */ 39624581Szliu 39724581Szliu hy=y/2.0; 39824581Szliu if(x>hy||((x==hy)&&n%2==1)) x-=y; 39924581Szliu px[n0] ^= sign; 40024581Szliu if(nf!=0) { t=1.0; pt[n0]-=nf; x*=t;} 40124581Szliu 40224581Szliu /* restore inexact flag and inexact enable */ 40324581Szliu swapINX(i); swapENI(e); 40424581Szliu 40524581Szliu return(x); 40624581Szliu } 40724581Szliu #endif 40824581Szliu 40924581Szliu #if 0 41024581Szliu /* SQRT 41124581Szliu * RETURN CORRECTLY ROUNDED (ACCORDING TO THE ROUNDING MODE) SQRT 41224581Szliu * FOR IEEE DOUBLE PRECISION ONLY, INTENDED FOR ASSEMBLY LANGUAGE 41324581Szliu * CODED IN C BY K.C. NG, 3/22/85. 41424581Szliu * 41524581Szliu * Warning: this code should not get compiled in unless ALL of 41624581Szliu * the following machine-dependent routines are supplied. 41724581Szliu * 41824581Szliu * Required machine dependent functions: 41924581Szliu * swapINX(i) ...return the status of INEXACT flag and reset it to "i" 42024581Szliu * swapRM(r) ...return the current Rounding Mode and reset it to "r" 42124581Szliu * swapENI(e) ...return the status of inexact enable and reset it to "e" 42224581Szliu * addc(t) ...perform t=t+1 regarding t as a 64 bit unsigned integer 42324581Szliu * subc(t) ...perform t=t-1 regarding t as a 64 bit unsigned integer 42424581Szliu */ 42524581Szliu 42635681Sbostic static const unsigned long table[] = { 42724581Szliu 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, 29598, 36145, 43202, 50740, 42824581Szliu 58733, 67158, 75992, 85215, 83599, 71378, 60428, 50647, 41945, 34246, 27478, 42924581Szliu 21581, 16499, 12183, 8588, 5674, 3403, 1742, 661, 130, }; 43024581Szliu 43124581Szliu double newsqrt(x) 43224581Szliu double x; 43324581Szliu { 43435681Sbostic double y,z,t,addc(),subc() 43535681Sbostic double const b54=134217728.*134217728.; /* b54=2**54 */ 43635681Sbostic long mx,scalx; 43735681Sbostic long const mexp=0x7ff00000; 43824581Szliu int i,j,r,e,swapINX(),swapRM(),swapENI(); 43924581Szliu unsigned long *py=(unsigned long *) &y , 44024581Szliu *pt=(unsigned long *) &t , 44124581Szliu *px=(unsigned long *) &x ; 44231856Szliu #ifdef national /* ordering of word in a floating point number */ 44335681Sbostic const int n0=1, n1=0; 44424581Szliu #else 44535681Sbostic const int n0=0, n1=1; 44624581Szliu #endif 44724581Szliu /* Rounding Mode: RN ...round-to-nearest 44824581Szliu * RZ ...round-towards 0 44924581Szliu * RP ...round-towards +INF 45024581Szliu * RM ...round-towards -INF 45124581Szliu */ 45235681Sbostic const int RN=0,RZ=1,RP=2,RM=3; 45335681Sbostic /* machine dependent: work on a Zilog Z8070 45424581Szliu * and a National 32081 & 16081 45524581Szliu */ 45624581Szliu 45724581Szliu /* exceptions */ 45824581Szliu if(x!=x||x==0.0) return(x); /* sqrt(NaN) is NaN, sqrt(+-0) = +-0 */ 45924581Szliu if(x<0) return((x-x)/(x-x)); /* sqrt(negative) is invalid */ 46024581Szliu if((mx=px[n0]&mexp)==mexp) return(x); /* sqrt(+INF) is +INF */ 46124581Szliu 46224581Szliu /* save, reset, initialize */ 46324581Szliu e=swapENI(0); /* ...save and reset the inexact enable */ 46424581Szliu i=swapINX(0); /* ...save INEXACT flag */ 46524581Szliu r=swapRM(RN); /* ...save and reset the Rounding Mode to RN */ 46624581Szliu scalx=0; 46724581Szliu 46824581Szliu /* subnormal number, scale up x to x*2**54 */ 46924581Szliu if(mx==0) {x *= b54 ; scalx-=0x01b00000;} 47024581Szliu 47124581Szliu /* scale x to avoid intermediate over/underflow: 47224581Szliu * if (x > 2**512) x=x/2**512; if (x < 2**-512) x=x*2**512 */ 47324581Szliu if(mx>0x5ff00000) {px[n0] -= 0x20000000; scalx+= 0x10000000;} 47424581Szliu if(mx<0x1ff00000) {px[n0] += 0x20000000; scalx-= 0x10000000;} 47524581Szliu 47624581Szliu /* magic initial approximation to almost 8 sig. bits */ 47724581Szliu py[n0]=(px[n0]>>1)+0x1ff80000; 47824581Szliu py[n0]=py[n0]-table[(py[n0]>>15)&31]; 47924581Szliu 48024581Szliu /* Heron's rule once with correction to improve y to almost 18 sig. bits */ 48124581Szliu t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; 48224581Szliu 48324581Szliu /* triple to almost 56 sig. bits; now y approx. sqrt(x) to within 1 ulp */ 48424581Szliu t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; 48524581Szliu t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; 48624581Szliu 48724581Szliu /* twiddle last bit to force y correctly rounded */ 48824581Szliu swapRM(RZ); /* ...set Rounding Mode to round-toward-zero */ 48924581Szliu swapINX(0); /* ...clear INEXACT flag */ 49024581Szliu swapENI(e); /* ...restore inexact enable status */ 49124581Szliu t=x/y; /* ...chopped quotient, possibly inexact */ 49224581Szliu j=swapINX(i); /* ...read and restore inexact flag */ 49324581Szliu if(j==0) { if(t==y) goto end; else t=subc(t); } /* ...t=t-ulp */ 49424581Szliu b54+0.1; /* ..trigger inexact flag, sqrt(x) is inexact */ 49524581Szliu if(r==RN) t=addc(t); /* ...t=t+ulp */ 49624581Szliu else if(r==RP) { t=addc(t);y=addc(y);}/* ...t=t+ulp;y=y+ulp; */ 49724581Szliu y=y+t; /* ...chopped sum */ 49824581Szliu py[n0]=py[n0]-0x00100000; /* ...correctly rounded sqrt(x) */ 49924581Szliu end: py[n0]=py[n0]+scalx; /* ...scale back y */ 50024581Szliu swapRM(r); /* ...restore Rounding Mode */ 50124581Szliu return(y); 50224581Szliu } 50324581Szliu #endif 504