Home | History | Annotate | Line # | Download | only in noieee_src
      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