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