(root)/
gmp-6.3.0/
extract-dbl.c
       1  /* __gmp_extract_double -- convert from double to array of mp_limb_t.
       2  
       3  Copyright 1996, 1999-2002, 2006, 2012 Free Software Foundation, Inc.
       4  
       5  This file is part of the GNU MP Library.
       6  
       7  The GNU MP Library is free software; you can redistribute it and/or modify
       8  it under the terms of either:
       9  
      10    * the GNU Lesser General Public License as published by the Free
      11      Software Foundation; either version 3 of the License, or (at your
      12      option) any later version.
      13  
      14  or
      15  
      16    * the GNU General Public License as published by the Free Software
      17      Foundation; either version 2 of the License, or (at your option) any
      18      later version.
      19  
      20  or both in parallel, as here.
      21  
      22  The GNU MP Library is distributed in the hope that it will be useful, but
      23  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      24  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      25  for more details.
      26  
      27  You should have received copies of the GNU General Public License and the
      28  GNU Lesser General Public License along with the GNU MP Library.  If not,
      29  see https://www.gnu.org/licenses/.  */
      30  
      31  #include "gmp-impl.h"
      32  
      33  #ifdef XDEBUG
      34  #undef _GMP_IEEE_FLOATS
      35  #endif
      36  
      37  #ifndef _GMP_IEEE_FLOATS
      38  #define _GMP_IEEE_FLOATS 0
      39  #endif
      40  
      41  /* Extract a non-negative double in d.  */
      42  
      43  int
      44  __gmp_extract_double (mp_ptr rp, double d)
      45  {
      46    long exp;
      47    unsigned sc;
      48  #ifdef _LONG_LONG_LIMB
      49  #define BITS_PER_PART 64	/* somewhat bogus */
      50    unsigned long long int manl;
      51  #else
      52  #define BITS_PER_PART GMP_LIMB_BITS
      53    unsigned long int manh, manl;
      54  #endif
      55  
      56    /* BUGS
      57  
      58       1. Should handle Inf and NaN in IEEE specific code.
      59       2. Handle Inf and NaN also in default code, to avoid hangs.
      60       3. Generalize to handle all GMP_LIMB_BITS >= 32.
      61       4. This lits is incomplete and misspelled.
      62     */
      63  
      64    ASSERT (d >= 0.0);
      65  
      66    if (d == 0.0)
      67      {
      68        MPN_ZERO (rp, LIMBS_PER_DOUBLE);
      69        return 0;
      70      }
      71  
      72  #if _GMP_IEEE_FLOATS
      73    {
      74  #if defined (__alpha) && __GNUC__ == 2 && __GNUC_MINOR__ == 8
      75      /* Work around alpha-specific bug in GCC 2.8.x.  */
      76      volatile
      77  #endif
      78      union ieee_double_extract x;
      79      x.d = d;
      80      exp = x.s.exp;
      81  #if BITS_PER_PART == 64		/* generalize this to BITS_PER_PART > BITS_IN_MANTISSA */
      82      manl = (((mp_limb_t) 1 << 63)
      83  	    | ((mp_limb_t) x.s.manh << 43) | ((mp_limb_t) x.s.manl << 11));
      84      if (exp == 0)
      85        {
      86  	/* Denormalized number.  Don't try to be clever about this,
      87  	   since it is not an important case to make fast.  */
      88  	exp = 1;
      89  	do
      90  	  {
      91  	    manl = manl << 1;
      92  	    exp--;
      93  	  }
      94  	while ((manl & GMP_LIMB_HIGHBIT) == 0);
      95        }
      96  #endif
      97  #if BITS_PER_PART == 32
      98      manh = ((mp_limb_t) 1 << 31) | (x.s.manh << 11) | (x.s.manl >> 21);
      99      manl = x.s.manl << 11;
     100      if (exp == 0)
     101        {
     102  	/* Denormalized number.  Don't try to be clever about this,
     103  	   since it is not an important case to make fast.  */
     104  	exp = 1;
     105  	do
     106  	  {
     107  	    manh = (manh << 1) | (manl >> 31);
     108  	    manl = manl << 1;
     109  	    exp--;
     110  	  }
     111  	while ((manh & GMP_LIMB_HIGHBIT) == 0);
     112        }
     113  #endif
     114  #if BITS_PER_PART != 32 && BITS_PER_PART != 64
     115    You need to generalize the code above to handle this.
     116  #endif
     117      exp -= 1022;		/* Remove IEEE bias.  */
     118    }
     119  #else
     120    {
     121      /* Unknown (or known to be non-IEEE) double format.  */
     122      exp = 0;
     123      if (d >= 1.0)
     124        {
     125  	ASSERT_ALWAYS (d * 0.5 != d);
     126  
     127  	while (d >= 32768.0)
     128  	  {
     129  	    d *= (1.0 / 65536.0);
     130  	    exp += 16;
     131  	  }
     132  	while (d >= 1.0)
     133  	  {
     134  	    d *= 0.5;
     135  	    exp += 1;
     136  	  }
     137        }
     138      else if (d < 0.5)
     139        {
     140  	while (d < (1.0 / 65536.0))
     141  	  {
     142  	    d *=  65536.0;
     143  	    exp -= 16;
     144  	  }
     145  	while (d < 0.5)
     146  	  {
     147  	    d *= 2.0;
     148  	    exp -= 1;
     149  	  }
     150        }
     151  
     152      d *= (4.0 * ((unsigned long int) 1 << (BITS_PER_PART - 2)));
     153  #if BITS_PER_PART == 64
     154      manl = d;
     155  #endif
     156  #if BITS_PER_PART == 32
     157      manh = d;
     158      manl = (d - manh) * (4.0 * ((unsigned long int) 1 << (BITS_PER_PART - 2)));
     159  #endif
     160    }
     161  #endif /* IEEE */
     162  
     163    sc = (unsigned) (exp + 64 * GMP_NUMB_BITS) % GMP_NUMB_BITS;
     164  
     165    /* We add something here to get rounding right.  */
     166    exp = (exp + 64 * GMP_NUMB_BITS) / GMP_NUMB_BITS - 64 * GMP_NUMB_BITS / GMP_NUMB_BITS + 1;
     167  
     168  #if BITS_PER_PART == 64 && LIMBS_PER_DOUBLE == 2
     169  #if GMP_NAIL_BITS == 0
     170    if (sc != 0)
     171      {
     172        rp[1] = manl >> (GMP_LIMB_BITS - sc);
     173        rp[0] = manl << sc;
     174      }
     175    else
     176      {
     177        rp[1] = manl;
     178        rp[0] = 0;
     179        exp--;
     180      }
     181  #else
     182    if (sc > GMP_NAIL_BITS)
     183      {
     184        rp[1] = manl >> (GMP_LIMB_BITS - sc);
     185        rp[0] = (manl << (sc - GMP_NAIL_BITS)) & GMP_NUMB_MASK;
     186      }
     187    else
     188      {
     189        if (sc == 0)
     190  	{
     191  	  rp[1] = manl >> GMP_NAIL_BITS;
     192  	  rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS) & GMP_NUMB_MASK;
     193  	  exp--;
     194  	}
     195        else
     196  	{
     197  	  rp[1] = manl >> (GMP_LIMB_BITS - sc);
     198  	  rp[0] = (manl >> (GMP_NAIL_BITS - sc)) & GMP_NUMB_MASK;
     199  	}
     200      }
     201  #endif
     202  #endif
     203  
     204  #if BITS_PER_PART == 64 && LIMBS_PER_DOUBLE == 3
     205    if (sc > GMP_NAIL_BITS)
     206      {
     207        rp[2] = manl >> (GMP_LIMB_BITS - sc);
     208        rp[1] = (manl << sc - GMP_NAIL_BITS) & GMP_NUMB_MASK;
     209        if (sc >= 2 * GMP_NAIL_BITS)
     210  	rp[0] = 0;
     211        else
     212  	rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS + sc) & GMP_NUMB_MASK;
     213      }
     214    else
     215      {
     216        if (sc == 0)
     217  	{
     218  	  rp[2] = manl >> GMP_NAIL_BITS;
     219  	  rp[1] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS) & GMP_NUMB_MASK;
     220  	  rp[0] = 0;
     221  	  exp--;
     222  	}
     223        else
     224  	{
     225  	  rp[2] = manl >> (GMP_LIMB_BITS - sc);
     226  	  rp[1] = (manl >> GMP_NAIL_BITS - sc) & GMP_NUMB_MASK;
     227  	  rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS + sc) & GMP_NUMB_MASK;
     228  	}
     229      }
     230  #endif
     231  
     232  #if BITS_PER_PART == 32 && LIMBS_PER_DOUBLE == 3
     233  #if GMP_NAIL_BITS == 0
     234    if (sc != 0)
     235      {
     236        rp[2] = manh >> (GMP_LIMB_BITS - sc);
     237        rp[1] = (manh << sc) | (manl >> (GMP_LIMB_BITS - sc));
     238        rp[0] = manl << sc;
     239      }
     240    else
     241      {
     242        rp[2] = manh;
     243        rp[1] = manl;
     244        rp[0] = 0;
     245        exp--;
     246      }
     247  #else
     248    if (sc > GMP_NAIL_BITS)
     249      {
     250        rp[2] = (manh >> (GMP_LIMB_BITS - sc));
     251        rp[1] = ((manh << (sc - GMP_NAIL_BITS)) |
     252  	       (manl >> (GMP_LIMB_BITS - sc + GMP_NAIL_BITS))) & GMP_NUMB_MASK;
     253        if (sc >= 2 * GMP_NAIL_BITS)
     254  	rp[0] = (manl << sc - 2 * GMP_NAIL_BITS) & GMP_NUMB_MASK;
     255        else
     256  	rp[0] = manl >> (2 * GMP_NAIL_BITS - sc) & GMP_NUMB_MASK;
     257      }
     258    else
     259      {
     260        if (sc == 0)
     261  	{
     262  	  rp[2] = manh >> GMP_NAIL_BITS;
     263  	  rp[1] = ((manh << GMP_NUMB_BITS - GMP_NAIL_BITS) | (manl >> 2 * GMP_NAIL_BITS)) & GMP_NUMB_MASK;
     264  	  rp[0] = (manl << GMP_NUMB_BITS - 2 * GMP_NAIL_BITS) & GMP_NUMB_MASK;
     265  	  exp--;
     266  	}
     267        else
     268  	{
     269  	  rp[2] = (manh >> (GMP_LIMB_BITS - sc));
     270  	  rp[1] = (manh >> (GMP_NAIL_BITS - sc)) & GMP_NUMB_MASK;
     271  	  rp[0] = ((manh << (GMP_NUMB_BITS - GMP_NAIL_BITS + sc))
     272  		   | (manl >> (GMP_LIMB_BITS - (GMP_NUMB_BITS - GMP_NAIL_BITS + sc)))) & GMP_NUMB_MASK;
     273  	}
     274      }
     275  #endif
     276  #endif
     277  
     278  #if BITS_PER_PART == 32 && LIMBS_PER_DOUBLE > 3
     279    if (sc == 0)
     280      {
     281        int i;
     282  
     283        for (i = LIMBS_PER_DOUBLE - 1; i >= 0; i--)
     284  	{
     285  	  rp[i] = manh >> (BITS_PER_ULONG - GMP_NUMB_BITS);
     286  	  manh = ((manh << GMP_NUMB_BITS)
     287  		  | (manl >> (BITS_PER_ULONG - GMP_NUMB_BITS)));
     288  	  manl = manl << GMP_NUMB_BITS;
     289  	}
     290        exp--;
     291      }
     292    else
     293      {
     294        int i;
     295  
     296        rp[LIMBS_PER_DOUBLE - 1] = (manh >> (GMP_LIMB_BITS - sc));
     297        manh = (manh << sc) | (manl >> (GMP_LIMB_BITS - sc));
     298        manl = (manl << sc);
     299        for (i = LIMBS_PER_DOUBLE - 2; i >= 0; i--)
     300  	{
     301  	  rp[i] = manh >> (BITS_PER_ULONG - GMP_NUMB_BITS);
     302  	  manh = ((manh << GMP_NUMB_BITS)
     303  		  | (manl >> (BITS_PER_ULONG - GMP_NUMB_BITS)));
     304  	  manl = manl << GMP_NUMB_BITS;
     305  	}
     306    }
     307  #endif
     308  
     309    return exp;
     310  }