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