linux/arch/mips/math-emu/dp_sqrt.c
<<
>>
Prefs
   1/* IEEE754 floating point arithmetic
   2 * double precision square root
   3 */
   4/*
   5 * MIPS floating point support
   6 * Copyright (C) 1994-2000 Algorithmics Ltd.
   7 *
   8 *  This program is free software; you can distribute it and/or modify it
   9 *  under the terms of the GNU General Public License (Version 2) as
  10 *  published by the Free Software Foundation.
  11 *
  12 *  This program is distributed in the hope it will be useful, but WITHOUT
  13 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15 *  for more details.
  16 *
  17 *  You should have received a copy of the GNU General Public License along
  18 *  with this program; if not, write to the Free Software Foundation, Inc.,
  19 *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  20 */
  21
  22#include "ieee754dp.h"
  23
  24static const unsigned int table[] = {
  25        0, 1204, 3062, 5746, 9193, 13348, 18162, 23592,
  26        29598, 36145, 43202, 50740, 58733, 67158, 75992,
  27        85215, 83599, 71378, 60428, 50647, 41945, 34246,
  28        27478, 21581, 16499, 12183, 8588, 5674, 3403,
  29        1742, 661, 130
  30};
  31
  32union ieee754dp ieee754dp_sqrt(union ieee754dp x)
  33{
  34        struct _ieee754_csr oldcsr;
  35        union ieee754dp y, z, t;
  36        unsigned int scalx, yh;
  37        COMPXDP;
  38
  39        EXPLODEXDP;
  40        ieee754_clearcx();
  41        FLUSHXDP;
  42
  43        /* x == INF or NAN? */
  44        switch (xc) {
  45        case IEEE754_CLASS_SNAN:
  46                return ieee754dp_nanxcpt(x);
  47
  48        case IEEE754_CLASS_QNAN:
  49                /* sqrt(Nan) = Nan */
  50                return x;
  51
  52        case IEEE754_CLASS_ZERO:
  53                /* sqrt(0) = 0 */
  54                return x;
  55
  56        case IEEE754_CLASS_INF:
  57                if (xs) {
  58                        /* sqrt(-Inf) = Nan */
  59                        ieee754_setcx(IEEE754_INVALID_OPERATION);
  60                        return ieee754dp_indef();
  61                }
  62                /* sqrt(+Inf) = Inf */
  63                return x;
  64
  65        case IEEE754_CLASS_DNORM:
  66                DPDNORMX;
  67                /* fall through */
  68
  69        case IEEE754_CLASS_NORM:
  70                if (xs) {
  71                        /* sqrt(-x) = Nan */
  72                        ieee754_setcx(IEEE754_INVALID_OPERATION);
  73                        return ieee754dp_indef();
  74                }
  75                break;
  76        }
  77
  78        /* save old csr; switch off INX enable & flag; set RN rounding */
  79        oldcsr = ieee754_csr;
  80        ieee754_csr.mx &= ~IEEE754_INEXACT;
  81        ieee754_csr.sx &= ~IEEE754_INEXACT;
  82        ieee754_csr.rm = FPU_CSR_RN;
  83
  84        /* adjust exponent to prevent overflow */
  85        scalx = 0;
  86        if (xe > 512) {         /* x > 2**-512? */
  87                xe -= 512;      /* x = x / 2**512 */
  88                scalx += 256;
  89        } else if (xe < -512) { /* x < 2**-512? */
  90                xe += 512;      /* x = x * 2**512 */
  91                scalx -= 256;
  92        }
  93
  94        x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
  95        y = x;
  96
  97        /* magic initial approximation to almost 8 sig. bits */
  98        yh = y.bits >> 32;
  99        yh = (yh >> 1) + 0x1ff80000;
 100        yh = yh - table[(yh >> 15) & 31];
 101        y.bits = ((u64) yh << 32) | (y.bits & 0xffffffff);
 102
 103        /* Heron's rule once with correction to improve to ~18 sig. bits */
 104        /* t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; */
 105        t = ieee754dp_div(x, y);
 106        y = ieee754dp_add(y, t);
 107        y.bits -= 0x0010000600000000LL;
 108        y.bits &= 0xffffffff00000000LL;
 109
 110        /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */
 111        /* t=y*y; z=t;  pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */
 112        t = ieee754dp_mul(y, y);
 113        z = t;
 114        t.bexp += 0x001;
 115        t = ieee754dp_add(t, z);
 116        z = ieee754dp_mul(ieee754dp_sub(x, z), y);
 117
 118        /* t=z/(t+x) ;  pt[n0]+=0x00100000; y+=t; */
 119        t = ieee754dp_div(z, ieee754dp_add(t, x));
 120        t.bexp += 0x001;
 121        y = ieee754dp_add(y, t);
 122
 123        /* twiddle last bit to force y correctly rounded */
 124
 125        /* set RZ, clear INEX flag */
 126        ieee754_csr.rm = FPU_CSR_RZ;
 127        ieee754_csr.sx &= ~IEEE754_INEXACT;
 128
 129        /* t=x/y; ...chopped quotient, possibly inexact */
 130        t = ieee754dp_div(x, y);
 131
 132        if (ieee754_csr.sx & IEEE754_INEXACT || t.bits != y.bits) {
 133
 134                if (!(ieee754_csr.sx & IEEE754_INEXACT))
 135                        /* t = t-ulp */
 136                        t.bits -= 1;
 137
 138                /* add inexact to result status */
 139                oldcsr.cx |= IEEE754_INEXACT;
 140                oldcsr.sx |= IEEE754_INEXACT;
 141
 142                switch (oldcsr.rm) {
 143                case FPU_CSR_RU:
 144                        y.bits += 1;
 145                        /* fall through */
 146                case FPU_CSR_RN:
 147                        t.bits += 1;
 148                        break;
 149                }
 150
 151                /* y=y+t; ...chopped sum */
 152                y = ieee754dp_add(y, t);
 153
 154                /* adjust scalx for correctly rounded sqrt(x) */
 155                scalx -= 1;
 156        }
 157
 158        /* py[n0]=py[n0]+scalx; ...scale back y */
 159        y.bexp += scalx;
 160
 161        /* restore rounding mode, possibly set inexact */
 162        ieee754_csr = oldcsr;
 163
 164        return y;
 165}
 166