2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 static char sccsid
[] = "@(#)support.c 8.1 (Berkeley) 6/4/93";
39 * Some IEEE standard 754 recommended functions and remainder and sqrt for
40 * supporting the C elementary functions.
41 ******************************************************************************
43 * These codes are developed (in double) to support the C elementary
44 * functions temporarily. They are not universal, and some of them are very
45 * slow (in particular, drem and sqrt is extremely inefficient). Each
46 * computer system should have its implementation of these functions using
48 ******************************************************************************
50 * IEEE 754 required operations:
52 * returns x REM y = x - [x/y]*y , where [x/y] is the integer
53 * nearest x/y; in half way case, choose the even one.
55 * returns the square root of x correctly rounded according to
58 * IEEE 754 recommended functions:
60 * returns x with the sign of y.
62 * returns x * (2**N), for integer values N.
64 * returns the unbiased exponent of x, a signed integer in
65 * double precision, except that logb(0) is -INF, logb(INF)
66 * is +INF, and logb(NAN) is that NAN.
68 * returns the value TRUE if -INF < x < +INF and returns
72 * CODED IN C BY K.C. NG, 11/25/84;
73 * REVISED BY K.C. NG on 1/22/85, 2/13/85, 3/24/85.
78 #if defined(vax)||defined(tahoe) /* VAX D format */
80 static const unsigned short msign
=0x7fff , mexp
=0x7f80 ;
81 static const short prep1
=57, gap
=7, bias
=129 ;
82 static const double novf
=1.7E38
, nunf
=3.0E-39, zero
=0.0 ;
83 #else /* defined(vax)||defined(tahoe) */
84 static const unsigned short msign
=0x7fff, mexp
=0x7ff0 ;
85 static const short prep1
=54, gap
=4, bias
=1023 ;
86 static const double novf
=1.7E308
, nunf
=3.0E-308,zero
=0.0;
87 #endif /* defined(vax)||defined(tahoe) */
95 unsigned short *px
=(unsigned short *) &x
+ 3;
97 unsigned short *px
=(unsigned short *) &x
;
100 if( x
== zero
) return(x
);
102 #if defined(vax)||defined(tahoe)
103 if( (k
= *px
& mexp
) != ~msign
) {
107 return(copysign(infnan(ERANGE
),x
));
109 #else /* defined(vax)||defined(tahoe) */
110 if( (k
= *px
& mexp
) != mexp
) {
111 if( N
<-2100) return(nunf
*nunf
); else if(N
>2100) return(novf
+novf
);
113 x
*= scalb(1.0,(int)prep1
); N
-= prep1
; return(scalb(x
,N
));}
114 #endif /* defined(vax)||defined(tahoe) */
116 if((k
= (k
>>gap
)+ N
) > 0 )
117 if( k
< (mexp
>>gap
) ) *px
= (*px
&~mexp
) | (k
<<gap
);
118 else x
=novf
+novf
; /* overflow */
121 /* gradual underflow */
122 {*px
=(*px
&~mexp
)|(short)(1<<gap
); x
*= scalb(1.0,k
-1);}
134 unsigned short *px
=(unsigned short *) &x
+3,
135 *py
=(unsigned short *) &y
+3;
137 unsigned short *px
=(unsigned short *) &x
,
138 *py
=(unsigned short *) &y
;
139 #endif /* national */
141 #if defined(vax)||defined(tahoe)
142 if ( (*px
& mexp
) == 0 ) return(x
);
143 #endif /* defined(vax)||defined(tahoe) */
145 *px
= ( *px
& msign
) | ( *py
& ~msign
);
154 short *px
=(short *) &x
+3, k
;
156 short *px
=(short *) &x
, k
;
157 #endif /* national */
159 #if defined(vax)||defined(tahoe)
160 return (int)(((*px
&mexp
)>>gap
)-bias
);
161 #else /* defined(vax)||defined(tahoe) */
162 if( (k
= *px
& mexp
) != mexp
)
164 return ( (k
>>gap
) - bias
);
172 {*px
&= msign
; return(x
);}
173 #endif /* defined(vax)||defined(tahoe) */
179 #if defined(vax)||defined(tahoe)
181 #else /* defined(vax)||defined(tahoe) */
183 return( (*((short *) &x
+3 ) & mexp
) != mexp
);
185 return( (*((short *) &x
) & mexp
) != mexp
);
186 #endif /* national */
187 #endif /* defined(vax)||defined(tahoe) */
198 *px
=(unsigned short *) &x
+3,
199 *pp
=(unsigned short *) &p
+3,
200 *pd
=(unsigned short *) &dp
+3,
201 *pt
=(unsigned short *) &tmp
+3;
204 *px
=(unsigned short *) &x
,
205 *pp
=(unsigned short *) &p
,
206 *pd
=(unsigned short *) &dp
,
207 *pt
=(unsigned short *) &tmp
;
208 #endif /* national */
212 #if defined(vax)||defined(tahoe)
213 if( ( *px
& mexp
) == ~msign
) /* is x a reserved operand? */
214 #else /* defined(vax)||defined(tahoe) */
215 if( ( *px
& mexp
) == mexp
)
216 #endif /* defined(vax)||defined(tahoe) */
217 return (x
-p
)-(x
-p
); /* create nan if x is inf */
219 #if defined(vax)||defined(tahoe)
220 return(infnan(EDOM
));
221 #else /* defined(vax)||defined(tahoe) */
223 #endif /* defined(vax)||defined(tahoe) */
226 #if defined(vax)||defined(tahoe)
227 if( ( *pp
& mexp
) == ~msign
) /* is p a reserved operand? */
228 #else /* defined(vax)||defined(tahoe) */
229 if( ( *pp
& mexp
) == mexp
)
230 #endif /* defined(vax)||defined(tahoe) */
231 { if (p
!= p
) return p
; else return x
;}
233 else if ( ((*pp
& mexp
)>>gap
) <= 1 )
234 /* subnormal p, or almost subnormal p */
235 { double b
; b
=scalb(1.0,(int)prep1
);
236 p
*= b
; x
= drem(x
,p
); x
*= b
; return(drem(x
,p
)/b
);}
237 else if ( p
>= novf
/2)
238 { p
/= 2 ; x
/= 2; return(drem(x
,p
)*2);}
246 k
=(*px
& mexp
) - (*pd
& mexp
) ;
250 #if defined(vax)||defined(tahoe)
251 if( x
< tmp
) *pt
-= 128 ;
252 #else /* defined(vax)||defined(tahoe) */
253 if( x
< tmp
) *pt
-= 16 ;
254 #endif /* defined(vax)||defined(tahoe) */
259 { x
-= p
; if ( x
>= hp
) x
-= p
; }
261 #if defined(vax)||defined(tahoe)
263 #endif /* defined(vax)||defined(tahoe) */
276 double const zero
=0.0;
278 #if defined(vax)||defined(tahoe)
280 #else /* defined(vax)||defined(tahoe) */
282 #endif /* defined(vax)||defined(tahoe) */
284 /* sqrt(NaN) is NaN, sqrt(+-0) = +-0 */
285 if(x
!=x
||x
==zero
) return(x
);
287 /* sqrt(negative) is invalid */
289 #if defined(vax)||defined(tahoe)
290 return (infnan(EDOM
)); /* NaN */
291 #else /* defined(vax)||defined(tahoe) */
293 #endif /* defined(vax)||defined(tahoe) */
296 /* sqrt(INF) is INF */
297 if(!finite(x
)) return(x
);
299 /* scale x to [1,4) */
302 if((m
=logb(x
))!=0) x
=scalb(x
,-m
); /* subnormal number */
305 if((n
+n
)!=m
) {x
*= 2; m
-=1; n
=m
/2;}
307 /* generate sqrt(x) bit by bit (accumulating in q) */
308 q
=1.0; s
=4.0; x
-= 1.0; r
=1;
310 t
=s
+1; x
*= 4; r
/= 2;
312 s
=t
+t
+2, x
-= t
; q
+= r
;}
317 /* generate the last bit and determine the final rounding */
319 if(x
==zero
) goto end
; 100+r
; /* trigger inexact flag */
321 q
+=r
; x
-=s
; s
+= 2; s
*= 2; x
*= 4;
323 b
=1.0+3*r
/4; if(b
==1.0) goto end
; /* b==1 : Round-to-zero */
324 b
=1.0+r
/4; if(b
>1.0) t
=1; /* b>1 : Round-to-(+INF) */
325 if(t
>=0) q
+=r
; } /* else: Round-to-nearest */
329 b
=1.0+3*r
/4; if(b
==1.0) goto end
;
330 b
=1.0+r
/4; if(b
>1.0) t
=1;
333 end
: return(scalb(q
,n
));
338 * RETURN X REM Y =X-N*Y, N=[X/Y] ROUNDED (ROUNDED TO EVEN IN THE HALF WAY CASE)
339 * DOUBLE PRECISION (VAX D format 56 bits, IEEE DOUBLE 53 BITS)
340 * INTENDED FOR ASSEMBLY LANGUAGE
341 * CODED IN C BY K.C. NG, 3/23/85, 4/8/85.
343 * Warning: this code should not get compiled in unless ALL of
344 * the following machine-dependent routines are supplied.
346 * Required machine dependent functions (not on a VAX):
347 * swapINX(i): save inexact flag and reset it to "i"
348 * swapENI(e): save inexact enable and reset it to "e"
355 #ifdef national /* order of words in floating point number */
356 static const n0
=3,n1
=2,n2
=1,n3
=0;
357 #else /* VAX, SUN, ZILOG, TAHOE */
358 static const n0
=0,n1
=1,n2
=2,n3
=3;
361 static const unsigned short mexp
=0x7ff0, m25
=0x0190, m57
=0x0390;
362 static const double zero
=0.0;
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
;
372 xexp
= px
[n0
] & mexp
; /* exponent of x */
373 yexp
= py
[n0
] & mexp
; /* exponent of y */
374 sign
= px
[n0
] &0x8000; /* sign of x */
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
);
381 /* save the inexact flag and inexact enable in i and e respectively
382 * and reset them to zero
384 i
=swapINX(0); e
=swapENI(0);
386 /* subnormal number */
388 if(yexp
==0) {t
=1.0,pt
[n0
]+=m57
; y
*=t
; nx
=m57
;}
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
;}
397 /* mask off the least significant 27 bits of y */
398 t
=y
; pt
[n3
]=0; pt
[n2
]&=0xf800; y1
=t
;
400 /* LOOP: argument reduction on x whenever x > y */
406 xexp
=px
[n0
]&mexp
; /* exponent of x */
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
);
412 /* end while (x > y) */
414 if(nx
!=0) {t
=1.0; pt
[n0
]+=nx
; x
*=t
; nx
=0; goto loop
;}
416 /* final adjustment */
419 if(x
>hy
||((x
==hy
)&&n
%2==1)) x
-=y
;
421 if(nf
!=0) { t
=1.0; pt
[n0
]-=nf
; x
*=t
;}
423 /* restore inexact flag and inexact enable */
424 swapINX(i
); swapENI(e
);
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.
436 * Warning: this code should not get compiled in unless ALL of
437 * the following machine-dependent routines are supplied.
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
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, };
455 double y
,z
,t
,addc(),subc()
456 double const b54
=134217728.*134217728.; /* b54=2**54 */
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;
466 const int n0
=0, n1
=1;
468 /* Rounding Mode: RN ...round-to-nearest
469 * RZ ...round-towards 0
470 * RP ...round-towards +INF
471 * RM ...round-towards -INF
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
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 */
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 */
489 /* subnormal number, scale up x to x*2**54 */
490 if(mx
==0) {x
*= b54
; scalx
-=0x01b00000;}
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;}
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];
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;
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
;
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 */