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