|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1985 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that: (1) source distributions retain this entire copyright ! 7: * notice and comment, and (2) distributions including binaries display ! 8: * the following acknowledgement: ``This product includes software ! 9: * developed by the University of California, Berkeley and its contributors'' ! 10: * in the documentation or other materials provided with the distribution ! 11: * and in all advertising materials mentioning features or use of this ! 12: * software. Neither the name of the University nor the names of its ! 13: * contributors may be used to endorse or promote products derived ! 14: * from this software without specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: * ! 19: * All recipients should regard themselves as participants in an ongoing ! 20: * research project and hence should feel obligated to report their ! 21: * experiences (good or bad) with these elementary function codes, using ! 22: * the sendbug(8) program, to the authors. ! 23: */ ! 24: ! 25: #ifndef lint ! 26: static char sccsid[] = "@(#)support.c 5.5 (Berkeley) 6/1/90"; ! 27: #endif /* not lint */ ! 28: ! 29: /* ! 30: * Some IEEE standard 754 recommended functions and remainder and sqrt for ! 31: * supporting the C elementary functions. ! 32: ****************************************************************************** ! 33: * WARNING: ! 34: * These codes are developed (in double) to support the C elementary ! 35: * functions temporarily. They are not universal, and some of them are very ! 36: * slow (in particular, drem and sqrt is extremely inefficient). Each ! 37: * computer system should have its implementation of these functions using ! 38: * its own assembler. ! 39: ****************************************************************************** ! 40: * ! 41: * IEEE 754 required operations: ! 42: * drem(x,p) ! 43: * returns x REM y = x - [x/y]*y , where [x/y] is the integer ! 44: * nearest x/y; in half way case, choose the even one. ! 45: * sqrt(x) ! 46: * returns the square root of x correctly rounded according to ! 47: * the rounding mod. ! 48: * ! 49: * IEEE 754 recommended functions: ! 50: * (a) copysign(x,y) ! 51: * returns x with the sign of y. ! 52: * (b) scalb(x,N) ! 53: * returns x * (2**N), for integer values N. ! 54: * (c) logb(x) ! 55: * returns the unbiased exponent of x, a signed integer in ! 56: * double precision, except that logb(0) is -INF, logb(INF) ! 57: * is +INF, and logb(NAN) is that NAN. ! 58: * (d) finite(x) ! 59: * returns the value TRUE if -INF < x < +INF and returns ! 60: * FALSE otherwise. ! 61: * ! 62: * ! 63: * CODED IN C BY K.C. NG, 11/25/84; ! 64: * REVISED BY K.C. NG on 1/22/85, 2/13/85, 3/24/85. ! 65: */ ! 66: ! 67: #include "mathimpl.h" ! 68: ! 69: #if defined(vax)||defined(tahoe) /* VAX D format */ ! 70: #include <errno.h> ! 71: static const unsigned short msign=0x7fff , mexp =0x7f80 ; ! 72: static const short prep1=57, gap=7, bias=129 ; ! 73: static const double novf=1.7E38, nunf=3.0E-39, zero=0.0 ; ! 74: #else /* defined(vax)||defined(tahoe) */ ! 75: static const unsigned short msign=0x7fff, mexp =0x7ff0 ; ! 76: static const short prep1=54, gap=4, bias=1023 ; ! 77: static const double novf=1.7E308, nunf=3.0E-308,zero=0.0; ! 78: #endif /* defined(vax)||defined(tahoe) */ ! 79: ! 80: double scalb(x,N) ! 81: double x; int N; ! 82: { ! 83: int k; ! 84: ! 85: #ifdef national ! 86: unsigned short *px=(unsigned short *) &x + 3; ! 87: #else /* national */ ! 88: unsigned short *px=(unsigned short *) &x; ! 89: #endif /* national */ ! 90: ! 91: if( x == zero ) return(x); ! 92: ! 93: #if defined(vax)||defined(tahoe) ! 94: if( (k= *px & mexp ) != ~msign ) { ! 95: if (N < -260) ! 96: return(nunf*nunf); ! 97: else if (N > 260) { ! 98: return(copysign(infnan(ERANGE),x)); ! 99: } ! 100: #else /* defined(vax)||defined(tahoe) */ ! 101: if( (k= *px & mexp ) != mexp ) { ! 102: if( N<-2100) return(nunf*nunf); else if(N>2100) return(novf+novf); ! 103: if( k == 0 ) { ! 104: x *= scalb(1.0,(int)prep1); N -= prep1; return(scalb(x,N));} ! 105: #endif /* defined(vax)||defined(tahoe) */ ! 106: ! 107: if((k = (k>>gap)+ N) > 0 ) ! 108: if( k < (mexp>>gap) ) *px = (*px&~mexp) | (k<<gap); ! 109: else x=novf+novf; /* overflow */ ! 110: else ! 111: if( k > -prep1 ) ! 112: /* gradual underflow */ ! 113: {*px=(*px&~mexp)|(short)(1<<gap); x *= scalb(1.0,k-1);} ! 114: else ! 115: return(nunf*nunf); ! 116: } ! 117: return(x); ! 118: } ! 119: ! 120: ! 121: double copysign(x,y) ! 122: double x,y; ! 123: { ! 124: #ifdef national ! 125: unsigned short *px=(unsigned short *) &x+3, ! 126: *py=(unsigned short *) &y+3; ! 127: #else /* national */ ! 128: unsigned short *px=(unsigned short *) &x, ! 129: *py=(unsigned short *) &y; ! 130: #endif /* national */ ! 131: ! 132: #if defined(vax)||defined(tahoe) ! 133: if ( (*px & mexp) == 0 ) return(x); ! 134: #endif /* defined(vax)||defined(tahoe) */ ! 135: ! 136: *px = ( *px & msign ) | ( *py & ~msign ); ! 137: return(x); ! 138: } ! 139: ! 140: double logb(x) ! 141: double x; ! 142: { ! 143: ! 144: #ifdef national ! 145: short *px=(short *) &x+3, k; ! 146: #else /* national */ ! 147: short *px=(short *) &x, k; ! 148: #endif /* national */ ! 149: ! 150: #if defined(vax)||defined(tahoe) ! 151: return (int)(((*px&mexp)>>gap)-bias); ! 152: #else /* defined(vax)||defined(tahoe) */ ! 153: if( (k= *px & mexp ) != mexp ) ! 154: if ( k != 0 ) ! 155: return ( (k>>gap) - bias ); ! 156: else if( x != zero) ! 157: return ( -1022.0 ); ! 158: else ! 159: return(-(1.0/zero)); ! 160: else if(x != x) ! 161: return(x); ! 162: else ! 163: {*px &= msign; return(x);} ! 164: #endif /* defined(vax)||defined(tahoe) */ ! 165: } ! 166: ! 167: finite(x) ! 168: double x; ! 169: { ! 170: #if defined(vax)||defined(tahoe) ! 171: return(1); ! 172: #else /* defined(vax)||defined(tahoe) */ ! 173: #ifdef national ! 174: return( (*((short *) &x+3 ) & mexp ) != mexp ); ! 175: #else /* national */ ! 176: return( (*((short *) &x ) & mexp ) != mexp ); ! 177: #endif /* national */ ! 178: #endif /* defined(vax)||defined(tahoe) */ ! 179: } ! 180: ! 181: double drem(x,p) ! 182: double x,p; ! 183: { ! 184: short sign; ! 185: double hp,dp,tmp; ! 186: unsigned short k; ! 187: #ifdef national ! 188: unsigned short ! 189: *px=(unsigned short *) &x +3, ! 190: *pp=(unsigned short *) &p +3, ! 191: *pd=(unsigned short *) &dp +3, ! 192: *pt=(unsigned short *) &tmp+3; ! 193: #else /* national */ ! 194: unsigned short ! 195: *px=(unsigned short *) &x , ! 196: *pp=(unsigned short *) &p , ! 197: *pd=(unsigned short *) &dp , ! 198: *pt=(unsigned short *) &tmp; ! 199: #endif /* national */ ! 200: ! 201: *pp &= msign ; ! 202: ! 203: #if defined(vax)||defined(tahoe) ! 204: if( ( *px & mexp ) == ~msign ) /* is x a reserved operand? */ ! 205: #else /* defined(vax)||defined(tahoe) */ ! 206: if( ( *px & mexp ) == mexp ) ! 207: #endif /* defined(vax)||defined(tahoe) */ ! 208: return (x-p)-(x-p); /* create nan if x is inf */ ! 209: if (p == zero) { ! 210: #if defined(vax)||defined(tahoe) ! 211: return(infnan(EDOM)); ! 212: #else /* defined(vax)||defined(tahoe) */ ! 213: return zero/zero; ! 214: #endif /* defined(vax)||defined(tahoe) */ ! 215: } ! 216: ! 217: #if defined(vax)||defined(tahoe) ! 218: if( ( *pp & mexp ) == ~msign ) /* is p a reserved operand? */ ! 219: #else /* defined(vax)||defined(tahoe) */ ! 220: if( ( *pp & mexp ) == mexp ) ! 221: #endif /* defined(vax)||defined(tahoe) */ ! 222: { if (p != p) return p; else return x;} ! 223: ! 224: else if ( ((*pp & mexp)>>gap) <= 1 ) ! 225: /* subnormal p, or almost subnormal p */ ! 226: { double b; b=scalb(1.0,(int)prep1); ! 227: p *= b; x = drem(x,p); x *= b; return(drem(x,p)/b);} ! 228: else if ( p >= novf/2) ! 229: { p /= 2 ; x /= 2; return(drem(x,p)*2);} ! 230: else ! 231: { ! 232: dp=p+p; hp=p/2; ! 233: sign= *px & ~msign ; ! 234: *px &= msign ; ! 235: while ( x > dp ) ! 236: { ! 237: k=(*px & mexp) - (*pd & mexp) ; ! 238: tmp = dp ; ! 239: *pt += k ; ! 240: ! 241: #if defined(vax)||defined(tahoe) ! 242: if( x < tmp ) *pt -= 128 ; ! 243: #else /* defined(vax)||defined(tahoe) */ ! 244: if( x < tmp ) *pt -= 16 ; ! 245: #endif /* defined(vax)||defined(tahoe) */ ! 246: ! 247: x -= tmp ; ! 248: } ! 249: if ( x > hp ) ! 250: { x -= p ; if ( x >= hp ) x -= p ; } ! 251: ! 252: #if defined(vax)||defined(tahoe) ! 253: if (x) ! 254: #endif /* defined(vax)||defined(tahoe) */ ! 255: *px ^= sign; ! 256: return( x); ! 257: ! 258: } ! 259: } ! 260: ! 261: ! 262: double sqrt(x) ! 263: double x; ! 264: { ! 265: double q,s,b,r; ! 266: double t; ! 267: double const zero=0.0; ! 268: int m,n,i; ! 269: #if defined(vax)||defined(tahoe) ! 270: int k=54; ! 271: #else /* defined(vax)||defined(tahoe) */ ! 272: int k=51; ! 273: #endif /* defined(vax)||defined(tahoe) */ ! 274: ! 275: /* sqrt(NaN) is NaN, sqrt(+-0) = +-0 */ ! 276: if(x!=x||x==zero) return(x); ! 277: ! 278: /* sqrt(negative) is invalid */ ! 279: if(x<zero) { ! 280: #if defined(vax)||defined(tahoe) ! 281: return (infnan(EDOM)); /* NaN */ ! 282: #else /* defined(vax)||defined(tahoe) */ ! 283: return(zero/zero); ! 284: #endif /* defined(vax)||defined(tahoe) */ ! 285: } ! 286: ! 287: /* sqrt(INF) is INF */ ! 288: if(!finite(x)) return(x); ! 289: ! 290: /* scale x to [1,4) */ ! 291: n=logb(x); ! 292: x=scalb(x,-n); ! 293: if((m=logb(x))!=0) x=scalb(x,-m); /* subnormal number */ ! 294: m += n; ! 295: n = m/2; ! 296: if((n+n)!=m) {x *= 2; m -=1; n=m/2;} ! 297: ! 298: /* generate sqrt(x) bit by bit (accumulating in q) */ ! 299: q=1.0; s=4.0; x -= 1.0; r=1; ! 300: for(i=1;i<=k;i++) { ! 301: t=s+1; x *= 4; r /= 2; ! 302: if(t<=x) { ! 303: s=t+t+2, x -= t; q += r;} ! 304: else ! 305: s *= 2; ! 306: } ! 307: ! 308: /* generate the last bit and determine the final rounding */ ! 309: r/=2; x *= 4; ! 310: if(x==zero) goto end; 100+r; /* trigger inexact flag */ ! 311: if(s<x) { ! 312: q+=r; x -=s; s += 2; s *= 2; x *= 4; ! 313: t = (x-s)-5; ! 314: b=1.0+3*r/4; if(b==1.0) goto end; /* b==1 : Round-to-zero */ ! 315: b=1.0+r/4; if(b>1.0) t=1; /* b>1 : Round-to-(+INF) */ ! 316: if(t>=0) q+=r; } /* else: Round-to-nearest */ ! 317: else { ! 318: s *= 2; x *= 4; ! 319: t = (x-s)-1; ! 320: b=1.0+3*r/4; if(b==1.0) goto end; ! 321: b=1.0+r/4; if(b>1.0) t=1; ! 322: if(t>=0) q+=r; } ! 323: ! 324: end: return(scalb(q,n)); ! 325: } ! 326: ! 327: #if 0 ! 328: /* DREM(X,Y) ! 329: * RETURN X REM Y =X-N*Y, N=[X/Y] ROUNDED (ROUNDED TO EVEN IN THE HALF WAY CASE) ! 330: * DOUBLE PRECISION (VAX D format 56 bits, IEEE DOUBLE 53 BITS) ! 331: * INTENDED FOR ASSEMBLY LANGUAGE ! 332: * CODED IN C BY K.C. NG, 3/23/85, 4/8/85. ! 333: * ! 334: * Warning: this code should not get compiled in unless ALL of ! 335: * the following machine-dependent routines are supplied. ! 336: * ! 337: * Required machine dependent functions (not on a VAX): ! 338: * swapINX(i): save inexact flag and reset it to "i" ! 339: * swapENI(e): save inexact enable and reset it to "e" ! 340: */ ! 341: ! 342: double drem(x,y) ! 343: double x,y; ! 344: { ! 345: ! 346: #ifdef national /* order of words in floating point number */ ! 347: static const n0=3,n1=2,n2=1,n3=0; ! 348: #else /* VAX, SUN, ZILOG, TAHOE */ ! 349: static const n0=0,n1=1,n2=2,n3=3; ! 350: #endif ! 351: ! 352: static const unsigned short mexp =0x7ff0, m25 =0x0190, m57 =0x0390; ! 353: static const double zero=0.0; ! 354: double hy,y1,t,t1; ! 355: short k; ! 356: long n; ! 357: int i,e; ! 358: unsigned short xexp,yexp, *px =(unsigned short *) &x , ! 359: nx,nf, *py =(unsigned short *) &y , ! 360: sign, *pt =(unsigned short *) &t , ! 361: *pt1 =(unsigned short *) &t1 ; ! 362: ! 363: xexp = px[n0] & mexp ; /* exponent of x */ ! 364: yexp = py[n0] & mexp ; /* exponent of y */ ! 365: sign = px[n0] &0x8000; /* sign of x */ ! 366: ! 367: /* return NaN if x is NaN, or y is NaN, or x is INF, or y is zero */ ! 368: if(x!=x) return(x); if(y!=y) return(y); /* x or y is NaN */ ! 369: if( xexp == mexp ) return(zero/zero); /* x is INF */ ! 370: if(y==zero) return(y/y); ! 371: ! 372: /* save the inexact flag and inexact enable in i and e respectively ! 373: * and reset them to zero ! 374: */ ! 375: i=swapINX(0); e=swapENI(0); ! 376: ! 377: /* subnormal number */ ! 378: nx=0; ! 379: if(yexp==0) {t=1.0,pt[n0]+=m57; y*=t; nx=m57;} ! 380: ! 381: /* if y is tiny (biased exponent <= 57), scale up y to y*2**57 */ ! 382: if( yexp <= m57 ) {py[n0]+=m57; nx+=m57; yexp+=m57;} ! 383: ! 384: nf=nx; ! 385: py[n0] &= 0x7fff; ! 386: px[n0] &= 0x7fff; ! 387: ! 388: /* mask off the least significant 27 bits of y */ ! 389: t=y; pt[n3]=0; pt[n2]&=0xf800; y1=t; ! 390: ! 391: /* LOOP: argument reduction on x whenever x > y */ ! 392: loop: ! 393: while ( x > y ) ! 394: { ! 395: t=y; ! 396: t1=y1; ! 397: xexp=px[n0]&mexp; /* exponent of x */ ! 398: k=xexp-yexp-m25; ! 399: if(k>0) /* if x/y >= 2**26, scale up y so that x/y < 2**26 */ ! 400: {pt[n0]+=k;pt1[n0]+=k;} ! 401: n=x/t; x=(x-n*t1)-n*(t-t1); ! 402: } ! 403: /* end while (x > y) */ ! 404: ! 405: if(nx!=0) {t=1.0; pt[n0]+=nx; x*=t; nx=0; goto loop;} ! 406: ! 407: /* final adjustment */ ! 408: ! 409: hy=y/2.0; ! 410: if(x>hy||((x==hy)&&n%2==1)) x-=y; ! 411: px[n0] ^= sign; ! 412: if(nf!=0) { t=1.0; pt[n0]-=nf; x*=t;} ! 413: ! 414: /* restore inexact flag and inexact enable */ ! 415: swapINX(i); swapENI(e); ! 416: ! 417: return(x); ! 418: } ! 419: #endif ! 420: ! 421: #if 0 ! 422: /* SQRT ! 423: * RETURN CORRECTLY ROUNDED (ACCORDING TO THE ROUNDING MODE) SQRT ! 424: * FOR IEEE DOUBLE PRECISION ONLY, INTENDED FOR ASSEMBLY LANGUAGE ! 425: * CODED IN C BY K.C. NG, 3/22/85. ! 426: * ! 427: * Warning: this code should not get compiled in unless ALL of ! 428: * the following machine-dependent routines are supplied. ! 429: * ! 430: * Required machine dependent functions: ! 431: * swapINX(i) ...return the status of INEXACT flag and reset it to "i" ! 432: * swapRM(r) ...return the current Rounding Mode and reset it to "r" ! 433: * swapENI(e) ...return the status of inexact enable and reset it to "e" ! 434: * addc(t) ...perform t=t+1 regarding t as a 64 bit unsigned integer ! 435: * subc(t) ...perform t=t-1 regarding t as a 64 bit unsigned integer ! 436: */ ! 437: ! 438: static const unsigned long table[] = { ! 439: 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, 29598, 36145, 43202, 50740, ! 440: 58733, 67158, 75992, 85215, 83599, 71378, 60428, 50647, 41945, 34246, 27478, ! 441: 21581, 16499, 12183, 8588, 5674, 3403, 1742, 661, 130, }; ! 442: ! 443: double newsqrt(x) ! 444: double x; ! 445: { ! 446: double y,z,t,addc(),subc() ! 447: double const b54=134217728.*134217728.; /* b54=2**54 */ ! 448: long mx,scalx; ! 449: long const mexp=0x7ff00000; ! 450: int i,j,r,e,swapINX(),swapRM(),swapENI(); ! 451: unsigned long *py=(unsigned long *) &y , ! 452: *pt=(unsigned long *) &t , ! 453: *px=(unsigned long *) &x ; ! 454: #ifdef national /* ordering of word in a floating point number */ ! 455: const int n0=1, n1=0; ! 456: #else ! 457: const int n0=0, n1=1; ! 458: #endif ! 459: /* Rounding Mode: RN ...round-to-nearest ! 460: * RZ ...round-towards 0 ! 461: * RP ...round-towards +INF ! 462: * RM ...round-towards -INF ! 463: */ ! 464: const int RN=0,RZ=1,RP=2,RM=3; ! 465: /* machine dependent: work on a Zilog Z8070 ! 466: * and a National 32081 & 16081 ! 467: */ ! 468: ! 469: /* exceptions */ ! 470: if(x!=x||x==0.0) return(x); /* sqrt(NaN) is NaN, sqrt(+-0) = +-0 */ ! 471: if(x<0) return((x-x)/(x-x)); /* sqrt(negative) is invalid */ ! 472: if((mx=px[n0]&mexp)==mexp) return(x); /* sqrt(+INF) is +INF */ ! 473: ! 474: /* save, reset, initialize */ ! 475: e=swapENI(0); /* ...save and reset the inexact enable */ ! 476: i=swapINX(0); /* ...save INEXACT flag */ ! 477: r=swapRM(RN); /* ...save and reset the Rounding Mode to RN */ ! 478: scalx=0; ! 479: ! 480: /* subnormal number, scale up x to x*2**54 */ ! 481: if(mx==0) {x *= b54 ; scalx-=0x01b00000;} ! 482: ! 483: /* scale x to avoid intermediate over/underflow: ! 484: * if (x > 2**512) x=x/2**512; if (x < 2**-512) x=x*2**512 */ ! 485: if(mx>0x5ff00000) {px[n0] -= 0x20000000; scalx+= 0x10000000;} ! 486: if(mx<0x1ff00000) {px[n0] += 0x20000000; scalx-= 0x10000000;} ! 487: ! 488: /* magic initial approximation to almost 8 sig. bits */ ! 489: py[n0]=(px[n0]>>1)+0x1ff80000; ! 490: py[n0]=py[n0]-table[(py[n0]>>15)&31]; ! 491: ! 492: /* Heron's rule once with correction to improve y to almost 18 sig. bits */ ! 493: t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; ! 494: ! 495: /* triple to almost 56 sig. bits; now y approx. sqrt(x) to within 1 ulp */ ! 496: t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; ! 497: t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; ! 498: ! 499: /* twiddle last bit to force y correctly rounded */ ! 500: swapRM(RZ); /* ...set Rounding Mode to round-toward-zero */ ! 501: swapINX(0); /* ...clear INEXACT flag */ ! 502: swapENI(e); /* ...restore inexact enable status */ ! 503: t=x/y; /* ...chopped quotient, possibly inexact */ ! 504: j=swapINX(i); /* ...read and restore inexact flag */ ! 505: if(j==0) { if(t==y) goto end; else t=subc(t); } /* ...t=t-ulp */ ! 506: b54+0.1; /* ..trigger inexact flag, sqrt(x) is inexact */ ! 507: if(r==RN) t=addc(t); /* ...t=t+ulp */ ! 508: else if(r==RP) { t=addc(t);y=addc(y);}/* ...t=t+ulp;y=y+ulp; */ ! 509: y=y+t; /* ...chopped sum */ ! 510: py[n0]=py[n0]-0x00100000; /* ...correctly rounded sqrt(x) */ ! 511: end: py[n0]=py[n0]+scalx; /* ...scale back y */ ! 512: swapRM(r); /* ...restore Rounding Mode */ ! 513: return(y); ! 514: } ! 515: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.