134123Sbostic /*
2*61283Sbostic * Copyright (c) 1985, 1993
3*61283Sbostic * The Regents of the University of California. All rights reserved.
434123Sbostic *
542657Sbostic * %sccs.include.redist.c%
624581Szliu */
724581Szliu
824581Szliu #ifndef lint
9*61283Sbostic static char sccsid[] = "@(#)support.c 8.1 (Berkeley) 06/04/93";
1034123Sbostic #endif /* not lint */
1124581Szliu
1224581Szliu /*
1331828Szliu * Some IEEE standard 754 recommended functions and remainder and sqrt for
1424581Szliu * supporting the C elementary functions.
1524581Szliu ******************************************************************************
1624581Szliu * WARNING:
1724581Szliu * These codes are developed (in double) to support the C elementary
1824581Szliu * functions temporarily. They are not universal, and some of them are very
1924581Szliu * slow (in particular, drem and sqrt is extremely inefficient). Each
2024581Szliu * computer system should have its implementation of these functions using
2124581Szliu * its own assembler.
2224581Szliu ******************************************************************************
2324581Szliu *
2431828Szliu * IEEE 754 required operations:
2524581Szliu * drem(x,p)
2624581Szliu * returns x REM y = x - [x/y]*y , where [x/y] is the integer
2724581Szliu * nearest x/y; in half way case, choose the even one.
2824581Szliu * sqrt(x)
2924581Szliu * returns the square root of x correctly rounded according to
3024581Szliu * the rounding mod.
3124581Szliu *
3231828Szliu * IEEE 754 recommended functions:
3324581Szliu * (a) copysign(x,y)
3424581Szliu * returns x with the sign of y.
3524581Szliu * (b) scalb(x,N)
3624581Szliu * returns x * (2**N), for integer values N.
3724581Szliu * (c) logb(x)
3824581Szliu * returns the unbiased exponent of x, a signed integer in
3924581Szliu * double precision, except that logb(0) is -INF, logb(INF)
4024581Szliu * is +INF, and logb(NAN) is that NAN.
4124581Szliu * (d) finite(x)
4224581Szliu * returns the value TRUE if -INF < x < +INF and returns
4324581Szliu * FALSE otherwise.
4424581Szliu *
4524581Szliu *
4624581Szliu * CODED IN C BY K.C. NG, 11/25/84;
4724581Szliu * REVISED BY K.C. NG on 1/22/85, 2/13/85, 3/24/85.
4824581Szliu */
4924581Szliu
5035681Sbostic #include "mathimpl.h"
5124581Szliu
5231856Szliu #if defined(vax)||defined(tahoe) /* VAX D format */
5331828Szliu #include <errno.h>
5435681Sbostic static const unsigned short msign=0x7fff , mexp =0x7f80 ;
5535681Sbostic static const short prep1=57, gap=7, bias=129 ;
5635681Sbostic static const double novf=1.7E38, nunf=3.0E-39, zero=0.0 ;
5731856Szliu #else /* defined(vax)||defined(tahoe) */
5835681Sbostic static const unsigned short msign=0x7fff, mexp =0x7ff0 ;
5935681Sbostic static const short prep1=54, gap=4, bias=1023 ;
6035681Sbostic static const double novf=1.7E308, nunf=3.0E-308,zero=0.0;
6131856Szliu #endif /* defined(vax)||defined(tahoe) */
6224581Szliu
scalb(x,N)6324581Szliu double scalb(x,N)
6424581Szliu double x; int N;
6524581Szliu {
6624581Szliu int k;
6724581Szliu
6831856Szliu #ifdef national
6924581Szliu unsigned short *px=(unsigned short *) &x + 3;
7031856Szliu #else /* national */
7124581Szliu unsigned short *px=(unsigned short *) &x;
7231856Szliu #endif /* national */
7324581Szliu
7424581Szliu if( x == zero ) return(x);
7524581Szliu
7631856Szliu #if defined(vax)||defined(tahoe)
7724581Szliu if( (k= *px & mexp ) != ~msign ) {
7831828Szliu if (N < -260)
7931828Szliu return(nunf*nunf);
8031828Szliu else if (N > 260) {
8131828Szliu return(copysign(infnan(ERANGE),x));
8231828Szliu }
8331856Szliu #else /* defined(vax)||defined(tahoe) */
8424581Szliu if( (k= *px & mexp ) != mexp ) {
8524581Szliu if( N<-2100) return(nunf*nunf); else if(N>2100) return(novf+novf);
8624581Szliu if( k == 0 ) {
8724581Szliu x *= scalb(1.0,(int)prep1); N -= prep1; return(scalb(x,N));}
8831856Szliu #endif /* defined(vax)||defined(tahoe) */
8924581Szliu
9024581Szliu if((k = (k>>gap)+ N) > 0 )
9124581Szliu if( k < (mexp>>gap) ) *px = (*px&~mexp) | (k<<gap);
9224581Szliu else x=novf+novf; /* overflow */
9324581Szliu else
9424581Szliu if( k > -prep1 )
9524581Szliu /* gradual underflow */
9624581Szliu {*px=(*px&~mexp)|(short)(1<<gap); x *= scalb(1.0,k-1);}
9724581Szliu else
9824581Szliu return(nunf*nunf);
9924581Szliu }
10024581Szliu return(x);
10124581Szliu }
10224581Szliu
10324581Szliu
copysign(x,y)10424581Szliu double copysign(x,y)
10524581Szliu double x,y;
10624581Szliu {
10731856Szliu #ifdef national
10824581Szliu unsigned short *px=(unsigned short *) &x+3,
10924581Szliu *py=(unsigned short *) &y+3;
11031856Szliu #else /* national */
11124581Szliu unsigned short *px=(unsigned short *) &x,
11224581Szliu *py=(unsigned short *) &y;
11331856Szliu #endif /* national */
11424581Szliu
11531856Szliu #if defined(vax)||defined(tahoe)
11624581Szliu if ( (*px & mexp) == 0 ) return(x);
11731856Szliu #endif /* defined(vax)||defined(tahoe) */
11824581Szliu
11924581Szliu *px = ( *px & msign ) | ( *py & ~msign );
12024581Szliu return(x);
12124581Szliu }
12224581Szliu
logb(x)12324581Szliu double logb(x)
12424581Szliu double x;
12524581Szliu {
12624581Szliu
12731856Szliu #ifdef national
12824581Szliu short *px=(short *) &x+3, k;
12931856Szliu #else /* national */
13024581Szliu short *px=(short *) &x, k;
13131856Szliu #endif /* national */
13224581Szliu
13331856Szliu #if defined(vax)||defined(tahoe)
13427449Szliu return (int)(((*px&mexp)>>gap)-bias);
13531856Szliu #else /* defined(vax)||defined(tahoe) */
13624581Szliu if( (k= *px & mexp ) != mexp )
13724581Szliu if ( k != 0 )
13824581Szliu return ( (k>>gap) - bias );
13924581Szliu else if( x != zero)
14024581Szliu return ( -1022.0 );
14124581Szliu else
14224581Szliu return(-(1.0/zero));
14324581Szliu else if(x != x)
14424581Szliu return(x);
14524581Szliu else
14624581Szliu {*px &= msign; return(x);}
14731856Szliu #endif /* defined(vax)||defined(tahoe) */
14824581Szliu }
14924581Szliu
finite(x)15024581Szliu finite(x)
15124581Szliu double x;
15224581Szliu {
15331856Szliu #if defined(vax)||defined(tahoe)
15431828Szliu return(1);
15531856Szliu #else /* defined(vax)||defined(tahoe) */
15631856Szliu #ifdef national
15724581Szliu return( (*((short *) &x+3 ) & mexp ) != mexp );
15831856Szliu #else /* national */
15924581Szliu return( (*((short *) &x ) & mexp ) != mexp );
16031856Szliu #endif /* national */
16131856Szliu #endif /* defined(vax)||defined(tahoe) */
16224581Szliu }
16324581Szliu
drem(x,p)16424581Szliu double drem(x,p)
16524581Szliu double x,p;
16624581Szliu {
16724581Szliu short sign;
16835681Sbostic double hp,dp,tmp;
16924581Szliu unsigned short k;
17031856Szliu #ifdef national
17124581Szliu unsigned short
17224581Szliu *px=(unsigned short *) &x +3,
17324581Szliu *pp=(unsigned short *) &p +3,
17424581Szliu *pd=(unsigned short *) &dp +3,
17524581Szliu *pt=(unsigned short *) &tmp+3;
17631856Szliu #else /* national */
17724581Szliu unsigned short
17824581Szliu *px=(unsigned short *) &x ,
17924581Szliu *pp=(unsigned short *) &p ,
18024581Szliu *pd=(unsigned short *) &dp ,
18124581Szliu *pt=(unsigned short *) &tmp;
18231856Szliu #endif /* national */
18324581Szliu
18424581Szliu *pp &= msign ;
18524581Szliu
18631856Szliu #if defined(vax)||defined(tahoe)
18731828Szliu if( ( *px & mexp ) == ~msign ) /* is x a reserved operand? */
18831856Szliu #else /* defined(vax)||defined(tahoe) */
18931827Szliu if( ( *px & mexp ) == mexp )
19031856Szliu #endif /* defined(vax)||defined(tahoe) */
19131827Szliu return (x-p)-(x-p); /* create nan if x is inf */
19231828Szliu if (p == zero) {
19331856Szliu #if defined(vax)||defined(tahoe)
19431828Szliu return(infnan(EDOM));
19531856Szliu #else /* defined(vax)||defined(tahoe) */
19631828Szliu return zero/zero;
19731856Szliu #endif /* defined(vax)||defined(tahoe) */
19831828Szliu }
19931828Szliu
20031856Szliu #if defined(vax)||defined(tahoe)
20131828Szliu if( ( *pp & mexp ) == ~msign ) /* is p a reserved operand? */
20231856Szliu #else /* defined(vax)||defined(tahoe) */
20331827Szliu if( ( *pp & mexp ) == mexp )
20431856Szliu #endif /* defined(vax)||defined(tahoe) */
20531827Szliu { if (p != p) return p; else return x;}
20624581Szliu
20724581Szliu else if ( ((*pp & mexp)>>gap) <= 1 )
20824581Szliu /* subnormal p, or almost subnormal p */
20924581Szliu { double b; b=scalb(1.0,(int)prep1);
21024581Szliu p *= b; x = drem(x,p); x *= b; return(drem(x,p)/b);}
21124581Szliu else if ( p >= novf/2)
21224581Szliu { p /= 2 ; x /= 2; return(drem(x,p)*2);}
21324581Szliu else
21424581Szliu {
21524581Szliu dp=p+p; hp=p/2;
21624581Szliu sign= *px & ~msign ;
21724581Szliu *px &= msign ;
21824581Szliu while ( x > dp )
21924581Szliu {
22024581Szliu k=(*px & mexp) - (*pd & mexp) ;
22124581Szliu tmp = dp ;
22224581Szliu *pt += k ;
22324581Szliu
22431856Szliu #if defined(vax)||defined(tahoe)
22524581Szliu if( x < tmp ) *pt -= 128 ;
22631856Szliu #else /* defined(vax)||defined(tahoe) */
22724581Szliu if( x < tmp ) *pt -= 16 ;
22831856Szliu #endif /* defined(vax)||defined(tahoe) */
22924581Szliu
23024581Szliu x -= tmp ;
23124581Szliu }
23224581Szliu if ( x > hp )
23324581Szliu { x -= p ; if ( x >= hp ) x -= p ; }
23424581Szliu
23531856Szliu #if defined(vax)||defined(tahoe)
23631825Szliu if (x)
23731856Szliu #endif /* defined(vax)||defined(tahoe) */
23831825Szliu *px ^= sign;
23924581Szliu return( x);
24024581Szliu
24124581Szliu }
24224581Szliu }
24335681Sbostic
24435681Sbostic
sqrt(x)24524581Szliu double sqrt(x)
24624581Szliu double x;
24724581Szliu {
24824581Szliu double q,s,b,r;
24935681Sbostic double t;
25035681Sbostic double const zero=0.0;
25135681Sbostic int m,n,i;
25231856Szliu #if defined(vax)||defined(tahoe)
25324581Szliu int k=54;
25431856Szliu #else /* defined(vax)||defined(tahoe) */
25524581Szliu int k=51;
25631856Szliu #endif /* defined(vax)||defined(tahoe) */
25724581Szliu
25824581Szliu /* sqrt(NaN) is NaN, sqrt(+-0) = +-0 */
25924581Szliu if(x!=x||x==zero) return(x);
26024581Szliu
26124581Szliu /* sqrt(negative) is invalid */
26231828Szliu if(x<zero) {
26331856Szliu #if defined(vax)||defined(tahoe)
26431828Szliu return (infnan(EDOM)); /* NaN */
26531856Szliu #else /* defined(vax)||defined(tahoe) */
26631828Szliu return(zero/zero);
26731856Szliu #endif /* defined(vax)||defined(tahoe) */
26831828Szliu }
26924581Szliu
27024581Szliu /* sqrt(INF) is INF */
27124581Szliu if(!finite(x)) return(x);
27224581Szliu
27324581Szliu /* scale x to [1,4) */
27424581Szliu n=logb(x);
27524581Szliu x=scalb(x,-n);
27624581Szliu if((m=logb(x))!=0) x=scalb(x,-m); /* subnormal number */
27724581Szliu m += n;
27824581Szliu n = m/2;
27924581Szliu if((n+n)!=m) {x *= 2; m -=1; n=m/2;}
28024581Szliu
28124581Szliu /* generate sqrt(x) bit by bit (accumulating in q) */
28224581Szliu q=1.0; s=4.0; x -= 1.0; r=1;
28324581Szliu for(i=1;i<=k;i++) {
28424581Szliu t=s+1; x *= 4; r /= 2;
28524581Szliu if(t<=x) {
28624581Szliu s=t+t+2, x -= t; q += r;}
28724581Szliu else
28824581Szliu s *= 2;
28924581Szliu }
29024581Szliu
29124581Szliu /* generate the last bit and determine the final rounding */
29224581Szliu r/=2; x *= 4;
29324581Szliu if(x==zero) goto end; 100+r; /* trigger inexact flag */
29424581Szliu if(s<x) {
29524581Szliu q+=r; x -=s; s += 2; s *= 2; x *= 4;
29624581Szliu t = (x-s)-5;
29724581Szliu b=1.0+3*r/4; if(b==1.0) goto end; /* b==1 : Round-to-zero */
29824581Szliu b=1.0+r/4; if(b>1.0) t=1; /* b>1 : Round-to-(+INF) */
29924581Szliu if(t>=0) q+=r; } /* else: Round-to-nearest */
30024581Szliu else {
30124581Szliu s *= 2; x *= 4;
30224581Szliu t = (x-s)-1;
30324581Szliu b=1.0+3*r/4; if(b==1.0) goto end;
30424581Szliu b=1.0+r/4; if(b>1.0) t=1;
30524581Szliu if(t>=0) q+=r; }
30624581Szliu
30724581Szliu end: return(scalb(q,n));
30824581Szliu }
30924581Szliu
31024581Szliu #if 0
31124581Szliu /* DREM(X,Y)
31224581Szliu * RETURN X REM Y =X-N*Y, N=[X/Y] ROUNDED (ROUNDED TO EVEN IN THE HALF WAY CASE)
31324581Szliu * DOUBLE PRECISION (VAX D format 56 bits, IEEE DOUBLE 53 BITS)
31424581Szliu * INTENDED FOR ASSEMBLY LANGUAGE
31524581Szliu * CODED IN C BY K.C. NG, 3/23/85, 4/8/85.
31624581Szliu *
31724581Szliu * Warning: this code should not get compiled in unless ALL of
31824581Szliu * the following machine-dependent routines are supplied.
31924581Szliu *
32024581Szliu * Required machine dependent functions (not on a VAX):
32124581Szliu * swapINX(i): save inexact flag and reset it to "i"
32224581Szliu * swapENI(e): save inexact enable and reset it to "e"
32324581Szliu */
32424581Szliu
32524581Szliu double drem(x,y)
32624581Szliu double x,y;
32724581Szliu {
32824581Szliu
32931856Szliu #ifdef national /* order of words in floating point number */
33035681Sbostic static const n0=3,n1=2,n2=1,n3=0;
33131789Szliu #else /* VAX, SUN, ZILOG, TAHOE */
33235681Sbostic static const n0=0,n1=1,n2=2,n3=3;
33324581Szliu #endif
33424581Szliu
33535681Sbostic static const unsigned short mexp =0x7ff0, m25 =0x0190, m57 =0x0390;
33635681Sbostic static const double zero=0.0;
33724581Szliu double hy,y1,t,t1;
33824581Szliu short k;
33924581Szliu long n;
34024581Szliu int i,e;
34124581Szliu unsigned short xexp,yexp, *px =(unsigned short *) &x ,
34224581Szliu nx,nf, *py =(unsigned short *) &y ,
34324581Szliu sign, *pt =(unsigned short *) &t ,
34424581Szliu *pt1 =(unsigned short *) &t1 ;
34524581Szliu
34624581Szliu xexp = px[n0] & mexp ; /* exponent of x */
34724581Szliu yexp = py[n0] & mexp ; /* exponent of y */
34824581Szliu sign = px[n0] &0x8000; /* sign of x */
34924581Szliu
35024581Szliu /* return NaN if x is NaN, or y is NaN, or x is INF, or y is zero */
35124581Szliu if(x!=x) return(x); if(y!=y) return(y); /* x or y is NaN */
35224581Szliu if( xexp == mexp ) return(zero/zero); /* x is INF */
35324581Szliu if(y==zero) return(y/y);
35424581Szliu
35524581Szliu /* save the inexact flag and inexact enable in i and e respectively
35624581Szliu * and reset them to zero
35724581Szliu */
35824581Szliu i=swapINX(0); e=swapENI(0);
35924581Szliu
36024581Szliu /* subnormal number */
36124581Szliu nx=0;
36224581Szliu if(yexp==0) {t=1.0,pt[n0]+=m57; y*=t; nx=m57;}
36324581Szliu
36424581Szliu /* if y is tiny (biased exponent <= 57), scale up y to y*2**57 */
36524581Szliu if( yexp <= m57 ) {py[n0]+=m57; nx+=m57; yexp+=m57;}
36624581Szliu
36724581Szliu nf=nx;
36824581Szliu py[n0] &= 0x7fff;
36924581Szliu px[n0] &= 0x7fff;
37024581Szliu
37124581Szliu /* mask off the least significant 27 bits of y */
37224581Szliu t=y; pt[n3]=0; pt[n2]&=0xf800; y1=t;
37324581Szliu
37424581Szliu /* LOOP: argument reduction on x whenever x > y */
37524581Szliu loop:
37624581Szliu while ( x > y )
37724581Szliu {
37824581Szliu t=y;
37924581Szliu t1=y1;
38024581Szliu xexp=px[n0]&mexp; /* exponent of x */
38124581Szliu k=xexp-yexp-m25;
38224581Szliu if(k>0) /* if x/y >= 2**26, scale up y so that x/y < 2**26 */
38324581Szliu {pt[n0]+=k;pt1[n0]+=k;}
38424581Szliu n=x/t; x=(x-n*t1)-n*(t-t1);
38524581Szliu }
38624581Szliu /* end while (x > y) */
38724581Szliu
38824581Szliu if(nx!=0) {t=1.0; pt[n0]+=nx; x*=t; nx=0; goto loop;}
38924581Szliu
39024581Szliu /* final adjustment */
39124581Szliu
39224581Szliu hy=y/2.0;
39324581Szliu if(x>hy||((x==hy)&&n%2==1)) x-=y;
39424581Szliu px[n0] ^= sign;
39524581Szliu if(nf!=0) { t=1.0; pt[n0]-=nf; x*=t;}
39624581Szliu
39724581Szliu /* restore inexact flag and inexact enable */
39824581Szliu swapINX(i); swapENI(e);
39924581Szliu
40024581Szliu return(x);
40124581Szliu }
40224581Szliu #endif
40324581Szliu
40424581Szliu #if 0
40524581Szliu /* SQRT
40624581Szliu * RETURN CORRECTLY ROUNDED (ACCORDING TO THE ROUNDING MODE) SQRT
40724581Szliu * FOR IEEE DOUBLE PRECISION ONLY, INTENDED FOR ASSEMBLY LANGUAGE
40824581Szliu * CODED IN C BY K.C. NG, 3/22/85.
40924581Szliu *
41024581Szliu * Warning: this code should not get compiled in unless ALL of
41124581Szliu * the following machine-dependent routines are supplied.
41224581Szliu *
41324581Szliu * Required machine dependent functions:
41424581Szliu * swapINX(i) ...return the status of INEXACT flag and reset it to "i"
41524581Szliu * swapRM(r) ...return the current Rounding Mode and reset it to "r"
41624581Szliu * swapENI(e) ...return the status of inexact enable and reset it to "e"
41724581Szliu * addc(t) ...perform t=t+1 regarding t as a 64 bit unsigned integer
41824581Szliu * subc(t) ...perform t=t-1 regarding t as a 64 bit unsigned integer
41924581Szliu */
42024581Szliu
42135681Sbostic static const unsigned long table[] = {
42224581Szliu 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, 29598, 36145, 43202, 50740,
42324581Szliu 58733, 67158, 75992, 85215, 83599, 71378, 60428, 50647, 41945, 34246, 27478,
42424581Szliu 21581, 16499, 12183, 8588, 5674, 3403, 1742, 661, 130, };
42524581Szliu
42624581Szliu double newsqrt(x)
42724581Szliu double x;
42824581Szliu {
42935681Sbostic double y,z,t,addc(),subc()
43035681Sbostic double const b54=134217728.*134217728.; /* b54=2**54 */
43135681Sbostic long mx,scalx;
43235681Sbostic long const mexp=0x7ff00000;
43324581Szliu int i,j,r,e,swapINX(),swapRM(),swapENI();
43424581Szliu unsigned long *py=(unsigned long *) &y ,
43524581Szliu *pt=(unsigned long *) &t ,
43624581Szliu *px=(unsigned long *) &x ;
43731856Szliu #ifdef national /* ordering of word in a floating point number */
43835681Sbostic const int n0=1, n1=0;
43924581Szliu #else
44035681Sbostic const int n0=0, n1=1;
44124581Szliu #endif
44224581Szliu /* Rounding Mode: RN ...round-to-nearest
44324581Szliu * RZ ...round-towards 0
44424581Szliu * RP ...round-towards +INF
44524581Szliu * RM ...round-towards -INF
44624581Szliu */
44735681Sbostic const int RN=0,RZ=1,RP=2,RM=3;
44835681Sbostic /* machine dependent: work on a Zilog Z8070
44924581Szliu * and a National 32081 & 16081
45024581Szliu */
45124581Szliu
45224581Szliu /* exceptions */
45324581Szliu if(x!=x||x==0.0) return(x); /* sqrt(NaN) is NaN, sqrt(+-0) = +-0 */
45424581Szliu if(x<0) return((x-x)/(x-x)); /* sqrt(negative) is invalid */
45524581Szliu if((mx=px[n0]&mexp)==mexp) return(x); /* sqrt(+INF) is +INF */
45624581Szliu
45724581Szliu /* save, reset, initialize */
45824581Szliu e=swapENI(0); /* ...save and reset the inexact enable */
45924581Szliu i=swapINX(0); /* ...save INEXACT flag */
46024581Szliu r=swapRM(RN); /* ...save and reset the Rounding Mode to RN */
46124581Szliu scalx=0;
46224581Szliu
46324581Szliu /* subnormal number, scale up x to x*2**54 */
46424581Szliu if(mx==0) {x *= b54 ; scalx-=0x01b00000;}
46524581Szliu
46624581Szliu /* scale x to avoid intermediate over/underflow:
46724581Szliu * if (x > 2**512) x=x/2**512; if (x < 2**-512) x=x*2**512 */
46824581Szliu if(mx>0x5ff00000) {px[n0] -= 0x20000000; scalx+= 0x10000000;}
46924581Szliu if(mx<0x1ff00000) {px[n0] += 0x20000000; scalx-= 0x10000000;}
47024581Szliu
47124581Szliu /* magic initial approximation to almost 8 sig. bits */
47224581Szliu py[n0]=(px[n0]>>1)+0x1ff80000;
47324581Szliu py[n0]=py[n0]-table[(py[n0]>>15)&31];
47424581Szliu
47524581Szliu /* Heron's rule once with correction to improve y to almost 18 sig. bits */
47624581Szliu t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0;
47724581Szliu
47824581Szliu /* triple to almost 56 sig. bits; now y approx. sqrt(x) to within 1 ulp */
47924581Szliu t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y;
48024581Szliu t=z/(t+x) ; pt[n0]+=0x00100000; y+=t;
48124581Szliu
48224581Szliu /* twiddle last bit to force y correctly rounded */
48324581Szliu swapRM(RZ); /* ...set Rounding Mode to round-toward-zero */
48424581Szliu swapINX(0); /* ...clear INEXACT flag */
48524581Szliu swapENI(e); /* ...restore inexact enable status */
48624581Szliu t=x/y; /* ...chopped quotient, possibly inexact */
48724581Szliu j=swapINX(i); /* ...read and restore inexact flag */
48824581Szliu if(j==0) { if(t==y) goto end; else t=subc(t); } /* ...t=t-ulp */
48924581Szliu b54+0.1; /* ..trigger inexact flag, sqrt(x) is inexact */
49024581Szliu if(r==RN) t=addc(t); /* ...t=t+ulp */
49124581Szliu else if(r==RP) { t=addc(t);y=addc(y);}/* ...t=t+ulp;y=y+ulp; */
49224581Szliu y=y+t; /* ...chopped sum */
49324581Szliu py[n0]=py[n0]-0x00100000; /* ...correctly rounded sqrt(x) */
49424581Szliu end: py[n0]=py[n0]+scalx; /* ...scale back y */
49524581Szliu swapRM(r); /* ...restore Rounding Mode */
49624581Szliu return(y);
49724581Szliu }
49824581Szliu #endif
499