source: soft/giet_vm/giet_libs/math/sqrt.c @ 817

Last change on this file since 817 was 816, checked in by cfuguet, 9 years ago

Add a software integer version of the libmath/sqrt function.

Also a flag to enable/disable the use of hard FPU instructions is
add into the giet_config.h file.

File size: 5.5 KB
Line 
1#include "../math.h"
2#include "math_private.h"
3
4static const double one = 1.0, tiny = 1.0e-300;
5
6/* this function was taken from the uCLibc library
7 * Return correctly rounded sqrt.
8 * Method:
9 *   Bit by bit method using integer arithmetic. (Slow, but portable)
10 *   1. Normalization
11 *      Scale x to y in [1,4) with even powers of 2:
12 *      find an integer k such that  1 <= (y=x*2^(2k)) < 4, then
13 *              sqrt(x) = 2^k * sqrt(y)
14 *   2. Bit by bit computation
15 *      Let q  = sqrt(y) truncated to i bit after binary point (q = 1),
16 *           i                                                   0
17 *                                     i+1         2
18 *          s  = 2*q , and      y  =  2   * ( y - q  ).         (1)
19 *           i      i            i                 i
20 *
21 *      To compute q    from q , one checks whether
22 *                  i+1       i
23 *
24 *                            -(i+1) 2
25 *                      (q + 2      ) <= y.                     (2)
26 *                        i
27 *                                                            -(i+1)
28 *      If (2) is false, then q   = q ; otherwise q   = q  + 2      .
29 *                             i+1   i             i+1   i
30 *
31 *      With some algebric manipulation, it is not difficult to see
32 *      that (2) is equivalent to
33 *                             -(i+1)
34 *                      s  +  2       <= y                      (3)
35 *                       i                i
36 *
37 *      The advantage of (3) is that s  and y  can be computed by
38 *                                    i      i
39 *      the following recurrence formula:
40 *          if (3) is false
41 *
42 *          s     =  s  ,       y    = y   ;                    (4)
43 *           i+1      i          i+1    i
44 *
45 *          otherwise,
46 *                         -i                     -(i+1)
47 *          s     =  s  + 2  ,  y    = y  -  s  - 2             (5)
48 *           i+1      i          i+1    i     i
49 *
50 *      One may easily use induction to prove (4) and (5).
51 *      Note. Since the left hand side of (3) contain only i+2 bits,
52 *            it does not necessary to do a full (53-bit) comparison
53 *            in (3).
54 *   3. Final rounding
55 *      After generating the 53 bits result, we compute one more bit.
56 *      Together with the remainder, we can decide whether the
57 *      result is exact, bigger than 1/2ulp, or less than 1/2ulp
58 *      (it will never equal to 1/2ulp).
59 *      The rounding mode can be detected by checking whether
60 *      huge + tiny is equal to huge, and whether huge - tiny is
61 *      equal to huge for some floating point number "huge" and "tiny".
62 *
63 * Special cases:
64 *      sqrt(+-0) = +-0         ... exact
65 *      sqrt(inf) = inf
66 *      sqrt(-ve) = NaN         ... with invalid signal
67 *      sqrt(NaN) = NaN         ... with invalid signal for signaling NaN
68 *
69 * Other methods : see the appended file at the end of the program below.
70 *---------------
71 */
72static double __ieee754_sqrt(double x)
73{
74    double z;
75    int32_t sign = (int)0x80000000;
76    int32_t ix0,s0,q,m,t,i;
77    uint32_t r,t1,s1,ix1,q1;
78
79    EXTRACT_WORDS(ix0,ix1,x);
80
81    /* take care of Inf and NaN */
82    if((ix0&0x7ff00000)==0x7ff00000) {
83        return x*x+x;           /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
84                               sqrt(-inf)=sNaN */
85    }
86    /* take care of zero */
87    if(ix0<=0) {
88        if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
89        else if(ix0<0)
90            return (x-x)/(x-x);         /* sqrt(-ve) = sNaN */
91    }
92    /* normalize x */
93    m = (ix0>>20);
94    if(m==0) {                          /* subnormal x */
95        while(ix0==0) {
96            m -= 21;
97            ix0 |= (ix1>>11); ix1 <<= 21;
98        }
99        for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
100        m -= i-1;
101        ix0 |= (ix1>>(32-i));
102        ix1 <<= i;
103    }
104    m -= 1023;  /* unbias exponent */
105    ix0 = (ix0&0x000fffff)|0x00100000;
106    if(m&1){    /* odd m, double x to make it even */
107        ix0 += ix0 + ((ix1&sign)>>31);
108        ix1 += ix1;
109    }
110    m >>= 1;    /* m = [m/2] */
111
112    /* generate sqrt(x) bit by bit */
113    ix0 += ix0 + ((ix1&sign)>>31);
114    ix1 += ix1;
115    q = q1 = s0 = s1 = 0;       /* [q,q1] = sqrt(x) */
116    r = 0x00200000;             /* r = moving bit from right to left */
117
118    while(r!=0) {
119        t = s0+r;
120        if(t<=ix0) {
121            s0   = t+r;
122            ix0 -= t;
123            q   += r;
124        }
125        ix0 += ix0 + ((ix1&sign)>>31);
126        ix1 += ix1;
127        r>>=1;
128    }
129
130    r = sign;
131    while(r!=0) {
132        t1 = s1+r;
133        t  = s0;
134        if((t<ix0)||((t==ix0)&&(t1<=ix1))) {
135            s1  = t1+r;
136            if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
137            ix0 -= t;
138            if (ix1 < t1) ix0 -= 1;
139            ix1 -= t1;
140            q1  += r;
141        }
142        ix0 += ix0 + ((ix1&sign)>>31);
143        ix1 += ix1;
144        r>>=1;
145    }
146
147    /* use floating add to find out rounding direction */
148    if((ix0|ix1)!=0) {
149        z = one-tiny; /* trigger inexact flag */
150        if (z>=one) {
151            z = one+tiny;
152            if (q1==(uint32_t)0xffffffff) { q1=0; q += 1;}
153            else if (z>one) {
154                if (q1==(uint32_t)0xfffffffe) q+=1;
155                q1+=2;
156            } else
157                q1 += (q1&1);
158        }
159    }
160    ix0 = (q>>1)+0x3fe00000;
161    ix1 =  q1>>1;
162    if ((q&1)==1) ix1 |= sign;
163    ix0 += (m <<20);
164    INSERT_WORDS(z,ix0,ix1);
165    return z;
166}
167
168double sqrt(double x)
169{
170#if GIET_USE_HARD_FLOAT
171    double z;
172    __asm__ ("sqrt.d %0,%1" : "=f" (z) : "f" (x));
173    return z;
174#else
175    return __ieee754_sqrt(x);
176#endif
177}
178
179/*
180 * vim: ts=4 : sts=4 : sw=4 : et
181 */
Note: See TracBrowser for help on using the repository browser.