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