n_support.c revision 1.4 1 /* $NetBSD: n_support.c,v 1.4 2002/06/15 00:10:18 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 #include "trig.h"
79
80 #if defined(__vax__)||defined(tahoe) /* VAX D format */
81 #include <errno.h>
82 static const unsigned short msign=0x7fff , mexp =0x7f80 ;
83 static const short prep1=57, gap=7, bias=129 ;
84 static const double novf=1.7E38, nunf=3.0E-39 ;
85 #else /* defined(__vax__)||defined(tahoe) */
86 static const unsigned short msign=0x7fff, mexp =0x7ff0 ;
87 static const short prep1=54, gap=4, bias=1023 ;
88 static const double novf=1.7E308, nunf=3.0E-308;
89 #endif /* defined(__vax__)||defined(tahoe) */
90
91 double
92 scalb(double x, int N)
93 {
94 int k;
95
96 #ifdef national
97 unsigned short *px=(unsigned short *) &x + 3;
98 #else /* national */
99 unsigned short *px=(unsigned short *) &x;
100 #endif /* national */
101
102 if( x == __zero ) return(x);
103
104 #if defined(__vax__)||defined(tahoe)
105 if( (k= *px & mexp ) != ~msign ) {
106 if (N < -260)
107 return(nunf*nunf);
108 else if (N > 260) {
109 return(copysign(infnan(ERANGE),x));
110 }
111 #else /* defined(__vax__)||defined(tahoe) */
112 if( (k= *px & mexp ) != mexp ) {
113 if( N<-2100) return(nunf*nunf); else if(N>2100) return(novf+novf);
114 if( k == 0 ) {
115 x *= scalb(1.0,(int)prep1); N -= prep1; return(scalb(x,N));}
116 #endif /* defined(__vax__)||defined(tahoe) */
117
118 if((k = (k>>gap)+ N) > 0 )
119 if( k < (mexp>>gap) ) *px = (*px&~mexp) | (k<<gap);
120 else x=novf+novf; /* overflow */
121 else
122 if( k > -prep1 )
123 /* gradual underflow */
124 {*px=(*px&~mexp)|(short)(1<<gap); x *= scalb(1.0,k-1);}
125 else
126 return(nunf*nunf);
127 }
128 return(x);
129 }
130
131
132 double
133 copysign(double x, double y)
134 {
135 #ifdef national
136 unsigned short *px=(unsigned short *) &x+3,
137 *py=(unsigned short *) &y+3;
138 #else /* national */
139 unsigned short *px=(unsigned short *) &x,
140 *py=(unsigned short *) &y;
141 #endif /* national */
142
143 #if defined(__vax__)||defined(tahoe)
144 if ( (*px & mexp) == 0 ) return(x);
145 #endif /* defined(__vax__)||defined(tahoe) */
146
147 *px = ( *px & msign ) | ( *py & ~msign );
148 return(x);
149 }
150
151 double
152 logb(double x)
153 {
154
155 #ifdef national
156 short *px=(short *) &x+3, k;
157 #else /* national */
158 short *px=(short *) &x, k;
159 #endif /* national */
160
161 #if defined(__vax__)||defined(tahoe)
162 return (int)(((*px&mexp)>>gap)-bias);
163 #else /* defined(__vax__)||defined(tahoe) */
164 if( (k= *px & mexp ) != mexp )
165 if ( k != 0 )
166 return ( (k>>gap) - bias );
167 else if( x != __zero)
168 return ( -1022.0 );
169 else
170 return(-(1.0/__zero));
171 else if(x != x)
172 return(x);
173 else
174 {*px &= msign; return(x);}
175 #endif /* defined(__vax__)||defined(tahoe) */
176 }
177
178 int
179 finite(double x)
180 {
181 #if defined(__vax__)||defined(tahoe)
182 return(1);
183 #else /* defined(__vax__)||defined(tahoe) */
184 #ifdef national
185 return( (*((short *) &x+3 ) & mexp ) != mexp );
186 #else /* national */
187 return( (*((short *) &x ) & mexp ) != mexp );
188 #endif /* national */
189 #endif /* defined(__vax__)||defined(tahoe) */
190 }
191
192 double
193 drem(double x, double p)
194 {
195 short sign;
196 double hp,dp,tmp;
197 unsigned short k;
198 #ifdef national
199 unsigned short
200 *px=(unsigned short *) &x +3,
201 *pp=(unsigned short *) &p +3,
202 *pd=(unsigned short *) &dp +3,
203 *pt=(unsigned short *) &tmp+3;
204 #else /* national */
205 unsigned short
206 *px=(unsigned short *) &x ,
207 *pp=(unsigned short *) &p ,
208 *pd=(unsigned short *) &dp ,
209 *pt=(unsigned short *) &tmp;
210 #endif /* national */
211
212 *pp &= msign ;
213
214 #if defined(__vax__)||defined(tahoe)
215 if( ( *px & mexp ) == ~msign ) /* is x a reserved operand? */
216 #else /* defined(__vax__)||defined(tahoe) */
217 if( ( *px & mexp ) == mexp )
218 #endif /* defined(__vax__)||defined(tahoe) */
219 return (x-p)-(x-p); /* create nan if x is inf */
220 if (p == __zero) {
221 #if defined(__vax__)||defined(tahoe)
222 return(infnan(EDOM));
223 #else /* defined(__vax__)||defined(tahoe) */
224 return __zero/__zero;
225 #endif /* defined(__vax__)||defined(tahoe) */
226 }
227
228 #if defined(__vax__)||defined(tahoe)
229 if( ( *pp & mexp ) == ~msign ) /* is p a reserved operand? */
230 #else /* defined(__vax__)||defined(tahoe) */
231 if( ( *pp & mexp ) == mexp )
232 #endif /* defined(__vax__)||defined(tahoe) */
233 { if (p != p) return p; else return x;}
234
235 else if ( ((*pp & mexp)>>gap) <= 1 )
236 /* subnormal p, or almost subnormal p */
237 { double b; b=scalb(1.0,(int)prep1);
238 p *= b; x = drem(x,p); x *= b; return(drem(x,p)/b);}
239 else if ( p >= novf/2)
240 { p /= 2 ; x /= 2; return(drem(x,p)*2);}
241 else
242 {
243 dp=p+p; hp=p/2;
244 sign= *px & ~msign ;
245 *px &= msign ;
246 while ( x > dp )
247 {
248 k=(*px & mexp) - (*pd & mexp) ;
249 tmp = dp ;
250 *pt += k ;
251
252 #if defined(__vax__)||defined(tahoe)
253 if( x < tmp ) *pt -= 128 ;
254 #else /* defined(__vax__)||defined(tahoe) */
255 if( x < tmp ) *pt -= 16 ;
256 #endif /* defined(__vax__)||defined(tahoe) */
257
258 x -= tmp ;
259 }
260 if ( x > hp )
261 { x -= p ; if ( x >= hp ) x -= p ; }
262
263 #if defined(__vax__)||defined(tahoe)
264 if (x)
265 #endif /* defined(__vax__)||defined(tahoe) */
266 *px ^= sign;
267 return( x);
268
269 }
270 }
271
272
273 double
274 sqrt(double x)
275 {
276 double q,s,b,r;
277 double t;
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
353 drem(double x, double 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 double hy,y1,t,t1;
364 short k;
365 long n;
366 int i,e;
367 unsigned short xexp,yexp, *px =(unsigned short *) &x ,
368 nx,nf, *py =(unsigned short *) &y ,
369 sign, *pt =(unsigned short *) &t ,
370 *pt1 =(unsigned short *) &t1 ;
371
372 xexp = px[n0] & mexp ; /* exponent of x */
373 yexp = py[n0] & mexp ; /* exponent of y */
374 sign = px[n0] &0x8000; /* sign of x */
375
376 /* return NaN if x is NaN, or y is NaN, or x is INF, or y is zero */
377 if(x!=x) return(x); if(y!=y) return(y); /* x or y is NaN */
378 if( xexp == mexp ) return(__zero/__zero); /* x is INF */
379 if(y==__zero) return(y/y);
380
381 /* save the inexact flag and inexact enable in i and e respectively
382 * and reset them to zero
383 */
384 i=swapINX(0); e=swapENI(0);
385
386 /* subnormal number */
387 nx=0;
388 if(yexp==0) {t=1.0,pt[n0]+=m57; y*=t; nx=m57;}
389
390 /* if y is tiny (biased exponent <= 57), scale up y to y*2**57 */
391 if( yexp <= m57 ) {py[n0]+=m57; nx+=m57; yexp+=m57;}
392
393 nf=nx;
394 py[n0] &= 0x7fff;
395 px[n0] &= 0x7fff;
396
397 /* mask off the least significant 27 bits of y */
398 t=y; pt[n3]=0; pt[n2]&=0xf800; y1=t;
399
400 /* LOOP: argument reduction on x whenever x > y */
401 loop:
402 while ( x > y )
403 {
404 t=y;
405 t1=y1;
406 xexp=px[n0]&mexp; /* exponent of x */
407 k=xexp-yexp-m25;
408 if(k>0) /* if x/y >= 2**26, scale up y so that x/y < 2**26 */
409 {pt[n0]+=k;pt1[n0]+=k;}
410 n=x/t; x=(x-n*t1)-n*(t-t1);
411 }
412 /* end while (x > y) */
413
414 if(nx!=0) {t=1.0; pt[n0]+=nx; x*=t; nx=0; goto loop;}
415
416 /* final adjustment */
417
418 hy=y/2.0;
419 if(x>hy||((x==hy)&&n%2==1)) x-=y;
420 px[n0] ^= sign;
421 if(nf!=0) { t=1.0; pt[n0]-=nf; x*=t;}
422
423 /* restore inexact flag and inexact enable */
424 swapINX(i); swapENI(e);
425
426 return(x);
427 }
428 #endif
429
430 #if 0
431 /* SQRT
432 * RETURN CORRECTLY ROUNDED (ACCORDING TO THE ROUNDING MODE) SQRT
433 * FOR IEEE DOUBLE PRECISION ONLY, INTENDED FOR ASSEMBLY LANGUAGE
434 * CODED IN C BY K.C. NG, 3/22/85.
435 *
436 * Warning: this code should not get compiled in unless ALL of
437 * the following machine-dependent routines are supplied.
438 *
439 * Required machine dependent functions:
440 * swapINX(i) ...return the status of INEXACT flag and reset it to "i"
441 * swapRM(r) ...return the current Rounding Mode and reset it to "r"
442 * swapENI(e) ...return the status of inexact enable and reset it to "e"
443 * addc(t) ...perform t=t+1 regarding t as a 64 bit unsigned integer
444 * subc(t) ...perform t=t-1 regarding t as a 64 bit unsigned integer
445 */
446
447 static const unsigned long table[] = {
448 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, 29598, 36145, 43202, 50740,
449 58733, 67158, 75992, 85215, 83599, 71378, 60428, 50647, 41945, 34246, 27478,
450 21581, 16499, 12183, 8588, 5674, 3403, 1742, 661, 130, };
451
452 double
453 newsqrt(double x)
454 {
455 double y,z,t,addc(),subc()
456 double const b54=134217728.*134217728.; /* b54=2**54 */
457 long mx,scalx;
458 long const mexp=0x7ff00000;
459 int i,j,r,e,swapINX(),swapRM(),swapENI();
460 unsigned long *py=(unsigned long *) &y ,
461 *pt=(unsigned long *) &t ,
462 *px=(unsigned long *) &x ;
463 #ifdef national /* ordering of word in a floating point number */
464 const int n0=1, n1=0;
465 #else
466 const int n0=0, n1=1;
467 #endif
468 /* Rounding Mode: RN ...round-to-nearest
469 * RZ ...round-towards 0
470 * RP ...round-towards +INF
471 * RM ...round-towards -INF
472 */
473 const int RN=0,RZ=1,RP=2,RM=3;
474 /* machine dependent: work on a Zilog Z8070
475 * and a National 32081 & 16081
476 */
477
478 /* exceptions */
479 if(x!=x||x==0.0) return(x); /* sqrt(NaN) is NaN, sqrt(+-0) = +-0 */
480 if(x<0) return((x-x)/(x-x)); /* sqrt(negative) is invalid */
481 if((mx=px[n0]&mexp)==mexp) return(x); /* sqrt(+INF) is +INF */
482
483 /* save, reset, initialize */
484 e=swapENI(0); /* ...save and reset the inexact enable */
485 i=swapINX(0); /* ...save INEXACT flag */
486 r=swapRM(RN); /* ...save and reset the Rounding Mode to RN */
487 scalx=0;
488
489 /* subnormal number, scale up x to x*2**54 */
490 if(mx==0) {x *= b54 ; scalx-=0x01b00000;}
491
492 /* scale x to avoid intermediate over/underflow:
493 * if (x > 2**512) x=x/2**512; if (x < 2**-512) x=x*2**512 */
494 if(mx>0x5ff00000) {px[n0] -= 0x20000000; scalx+= 0x10000000;}
495 if(mx<0x1ff00000) {px[n0] += 0x20000000; scalx-= 0x10000000;}
496
497 /* magic initial approximation to almost 8 sig. bits */
498 py[n0]=(px[n0]>>1)+0x1ff80000;
499 py[n0]=py[n0]-table[(py[n0]>>15)&31];
500
501 /* Heron's rule once with correction to improve y to almost 18 sig. bits */
502 t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0;
503
504 /* triple to almost 56 sig. bits; now y approx. sqrt(x) to within 1 ulp */
505 t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y;
506 t=z/(t+x) ; pt[n0]+=0x00100000; y+=t;
507
508 /* twiddle last bit to force y correctly rounded */
509 swapRM(RZ); /* ...set Rounding Mode to round-toward-zero */
510 swapINX(0); /* ...clear INEXACT flag */
511 swapENI(e); /* ...restore inexact enable status */
512 t=x/y; /* ...chopped quotient, possibly inexact */
513 j=swapINX(i); /* ...read and restore inexact flag */
514 if(j==0) { if(t==y) goto end; else t=subc(t); } /* ...t=t-ulp */
515 b54+0.1; /* ..trigger inexact flag, sqrt(x) is inexact */
516 if(r==RN) t=addc(t); /* ...t=t+ulp */
517 else if(r==RP) { t=addc(t);y=addc(y);}/* ...t=t+ulp;y=y+ulp; */
518 y=y+t; /* ...chopped sum */
519 py[n0]=py[n0]-0x00100000; /* ...correctly rounded sqrt(x) */
520 end: py[n0]=py[n0]+scalx; /* ...scale back y */
521 swapRM(r); /* ...restore Rounding Mode */
522 return(y);
523 }
524 #endif
525