Blame extract-dbl.c

Packit 5c3484
/* __gmp_extract_double -- convert from double to array of mp_limb_t.
Packit 5c3484
Packit 5c3484
Copyright 1996, 1999-2002, 2006, 2012 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
Packit 5c3484
#ifdef XDEBUG
Packit 5c3484
#undef _GMP_IEEE_FLOATS
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#ifndef _GMP_IEEE_FLOATS
Packit 5c3484
#define _GMP_IEEE_FLOATS 0
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
/* Extract a non-negative double in d.  */
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
__gmp_extract_double (mp_ptr rp, double d)
Packit 5c3484
{
Packit 5c3484
  long exp;
Packit 5c3484
  unsigned sc;
Packit 5c3484
#ifdef _LONG_LONG_LIMB
Packit 5c3484
#define BITS_PER_PART 64	/* somewhat bogus */
Packit 5c3484
  unsigned long long int manl;
Packit 5c3484
#else
Packit 5c3484
#define BITS_PER_PART GMP_LIMB_BITS
Packit 5c3484
  unsigned long int manh, manl;
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
  /* BUGS
Packit 5c3484
Packit 5c3484
     1. Should handle Inf and NaN in IEEE specific code.
Packit 5c3484
     2. Handle Inf and NaN also in default code, to avoid hangs.
Packit 5c3484
     3. Generalize to handle all GMP_LIMB_BITS >= 32.
Packit 5c3484
     4. This lits is incomplete and misspelled.
Packit 5c3484
   */
Packit 5c3484
Packit 5c3484
  ASSERT (d >= 0.0);
Packit 5c3484
Packit 5c3484
  if (d == 0.0)
Packit 5c3484
    {
Packit 5c3484
      MPN_ZERO (rp, LIMBS_PER_DOUBLE);
Packit 5c3484
      return 0;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
#if _GMP_IEEE_FLOATS
Packit 5c3484
  {
Packit 5c3484
#if defined (__alpha) && __GNUC__ == 2 && __GNUC_MINOR__ == 8
Packit 5c3484
    /* Work around alpha-specific bug in GCC 2.8.x.  */
Packit 5c3484
    volatile
Packit 5c3484
#endif
Packit 5c3484
    union ieee_double_extract x;
Packit 5c3484
    x.d = d;
Packit 5c3484
    exp = x.s.exp;
Packit 5c3484
#if BITS_PER_PART == 64		/* generalize this to BITS_PER_PART > BITS_IN_MANTISSA */
Packit 5c3484
    manl = (((mp_limb_t) 1 << 63)
Packit 5c3484
	    | ((mp_limb_t) x.s.manh << 43) | ((mp_limb_t) x.s.manl << 11));
Packit 5c3484
    if (exp == 0)
Packit 5c3484
      {
Packit 5c3484
	/* Denormalized number.  Don't try to be clever about this,
Packit 5c3484
	   since it is not an important case to make fast.  */
Packit 5c3484
	exp = 1;
Packit 5c3484
	do
Packit 5c3484
	  {
Packit 5c3484
	    manl = manl << 1;
Packit 5c3484
	    exp--;
Packit 5c3484
	  }
Packit 5c3484
	while ((manl & GMP_LIMB_HIGHBIT) == 0);
Packit 5c3484
      }
Packit 5c3484
#endif
Packit 5c3484
#if BITS_PER_PART == 32
Packit 5c3484
    manh = ((mp_limb_t) 1 << 31) | (x.s.manh << 11) | (x.s.manl >> 21);
Packit 5c3484
    manl = x.s.manl << 11;
Packit 5c3484
    if (exp == 0)
Packit 5c3484
      {
Packit 5c3484
	/* Denormalized number.  Don't try to be clever about this,
Packit 5c3484
	   since it is not an important case to make fast.  */
Packit 5c3484
	exp = 1;
Packit 5c3484
	do
Packit 5c3484
	  {
Packit 5c3484
	    manh = (manh << 1) | (manl >> 31);
Packit 5c3484
	    manl = manl << 1;
Packit 5c3484
	    exp--;
Packit 5c3484
	  }
Packit 5c3484
	while ((manh & GMP_LIMB_HIGHBIT) == 0);
Packit 5c3484
      }
Packit 5c3484
#endif
Packit 5c3484
#if BITS_PER_PART != 32 && BITS_PER_PART != 64
Packit 5c3484
  You need to generalize the code above to handle this.
Packit 5c3484
#endif
Packit 5c3484
    exp -= 1022;		/* Remove IEEE bias.  */
Packit 5c3484
  }
Packit 5c3484
#else
Packit 5c3484
  {
Packit 5c3484
    /* Unknown (or known to be non-IEEE) double format.  */
Packit 5c3484
    exp = 0;
Packit 5c3484
    if (d >= 1.0)
Packit 5c3484
      {
Packit 5c3484
	ASSERT_ALWAYS (d * 0.5 != d);
Packit 5c3484
Packit 5c3484
	while (d >= 32768.0)
Packit 5c3484
	  {
Packit 5c3484
	    d *= (1.0 / 65536.0);
Packit 5c3484
	    exp += 16;
Packit 5c3484
	  }
Packit 5c3484
	while (d >= 1.0)
Packit 5c3484
	  {
Packit 5c3484
	    d *= 0.5;
Packit 5c3484
	    exp += 1;
Packit 5c3484
	  }
Packit 5c3484
      }
Packit 5c3484
    else if (d < 0.5)
Packit 5c3484
      {
Packit 5c3484
	while (d < (1.0 / 65536.0))
Packit 5c3484
	  {
Packit 5c3484
	    d *=  65536.0;
Packit 5c3484
	    exp -= 16;
Packit 5c3484
	  }
Packit 5c3484
	while (d < 0.5)
Packit 5c3484
	  {
Packit 5c3484
	    d *= 2.0;
Packit 5c3484
	    exp -= 1;
Packit 5c3484
	  }
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
    d *= (4.0 * ((unsigned long int) 1 << (BITS_PER_PART - 2)));
Packit 5c3484
#if BITS_PER_PART == 64
Packit 5c3484
    manl = d;
Packit 5c3484
#endif
Packit 5c3484
#if BITS_PER_PART == 32
Packit 5c3484
    manh = d;
Packit 5c3484
    manl = (d - manh) * (4.0 * ((unsigned long int) 1 << (BITS_PER_PART - 2)));
Packit 5c3484
#endif
Packit 5c3484
  }
Packit 5c3484
#endif /* IEEE */
Packit 5c3484
Packit 5c3484
  sc = (unsigned) (exp + 64 * GMP_NUMB_BITS) % GMP_NUMB_BITS;
Packit 5c3484
Packit 5c3484
  /* We add something here to get rounding right.  */
Packit 5c3484
  exp = (exp + 64 * GMP_NUMB_BITS) / GMP_NUMB_BITS - 64 * GMP_NUMB_BITS / GMP_NUMB_BITS + 1;
Packit 5c3484
Packit 5c3484
#if BITS_PER_PART == 64 && LIMBS_PER_DOUBLE == 2
Packit 5c3484
#if GMP_NAIL_BITS == 0
Packit 5c3484
  if (sc != 0)
Packit 5c3484
    {
Packit 5c3484
      rp[1] = manl >> (GMP_LIMB_BITS - sc);
Packit 5c3484
      rp[0] = manl << sc;
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      rp[1] = manl;
Packit 5c3484
      rp[0] = 0;
Packit 5c3484
      exp--;
Packit 5c3484
    }
Packit 5c3484
#else
Packit 5c3484
  if (sc > GMP_NAIL_BITS)
Packit 5c3484
    {
Packit 5c3484
      rp[1] = manl >> (GMP_LIMB_BITS - sc);
Packit 5c3484
      rp[0] = (manl << (sc - GMP_NAIL_BITS)) & GMP_NUMB_MASK;
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      if (sc == 0)
Packit 5c3484
	{
Packit 5c3484
	  rp[1] = manl >> GMP_NAIL_BITS;
Packit 5c3484
	  rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS) & GMP_NUMB_MASK;
Packit 5c3484
	  exp--;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  rp[1] = manl >> (GMP_LIMB_BITS - sc);
Packit 5c3484
	  rp[0] = (manl >> (GMP_NAIL_BITS - sc)) & GMP_NUMB_MASK;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if BITS_PER_PART == 64 && LIMBS_PER_DOUBLE == 3
Packit 5c3484
  if (sc > GMP_NAIL_BITS)
Packit 5c3484
    {
Packit 5c3484
      rp[2] = manl >> (GMP_LIMB_BITS - sc);
Packit 5c3484
      rp[1] = (manl << sc - GMP_NAIL_BITS) & GMP_NUMB_MASK;
Packit 5c3484
      if (sc >= 2 * GMP_NAIL_BITS)
Packit 5c3484
	rp[0] = 0;
Packit 5c3484
      else
Packit 5c3484
	rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS + sc) & GMP_NUMB_MASK;
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      if (sc == 0)
Packit 5c3484
	{
Packit 5c3484
	  rp[2] = manl >> GMP_NAIL_BITS;
Packit 5c3484
	  rp[1] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS) & GMP_NUMB_MASK;
Packit 5c3484
	  rp[0] = 0;
Packit 5c3484
	  exp--;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  rp[2] = manl >> (GMP_LIMB_BITS - sc);
Packit 5c3484
	  rp[1] = (manl >> GMP_NAIL_BITS - sc) & GMP_NUMB_MASK;
Packit 5c3484
	  rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS + sc) & GMP_NUMB_MASK;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if BITS_PER_PART == 32 && LIMBS_PER_DOUBLE == 3
Packit 5c3484
#if GMP_NAIL_BITS == 0
Packit 5c3484
  if (sc != 0)
Packit 5c3484
    {
Packit 5c3484
      rp[2] = manh >> (GMP_LIMB_BITS - sc);
Packit 5c3484
      rp[1] = (manh << sc) | (manl >> (GMP_LIMB_BITS - sc));
Packit 5c3484
      rp[0] = manl << sc;
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      rp[2] = manh;
Packit 5c3484
      rp[1] = manl;
Packit 5c3484
      rp[0] = 0;
Packit 5c3484
      exp--;
Packit 5c3484
    }
Packit 5c3484
#else
Packit 5c3484
  if (sc > GMP_NAIL_BITS)
Packit 5c3484
    {
Packit 5c3484
      rp[2] = (manh >> (GMP_LIMB_BITS - sc));
Packit 5c3484
      rp[1] = ((manh << (sc - GMP_NAIL_BITS)) |
Packit 5c3484
	       (manl >> (GMP_LIMB_BITS - sc + GMP_NAIL_BITS))) & GMP_NUMB_MASK;
Packit 5c3484
      if (sc >= 2 * GMP_NAIL_BITS)
Packit 5c3484
	rp[0] = (manl << sc - 2 * GMP_NAIL_BITS) & GMP_NUMB_MASK;
Packit 5c3484
      else
Packit 5c3484
	rp[0] = manl >> (2 * GMP_NAIL_BITS - sc) & GMP_NUMB_MASK;
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      if (sc == 0)
Packit 5c3484
	{
Packit 5c3484
	  rp[2] = manh >> GMP_NAIL_BITS;
Packit 5c3484
	  rp[1] = ((manh << GMP_NUMB_BITS - GMP_NAIL_BITS) | (manl >> 2 * GMP_NAIL_BITS)) & GMP_NUMB_MASK;
Packit 5c3484
	  rp[0] = (manl << GMP_NUMB_BITS - 2 * GMP_NAIL_BITS) & GMP_NUMB_MASK;
Packit 5c3484
	  exp--;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  rp[2] = (manh >> (GMP_LIMB_BITS - sc));
Packit 5c3484
	  rp[1] = (manh >> (GMP_NAIL_BITS - sc)) & GMP_NUMB_MASK;
Packit 5c3484
	  rp[0] = ((manh << (GMP_NUMB_BITS - GMP_NAIL_BITS + sc))
Packit 5c3484
		   | (manl >> (GMP_LIMB_BITS - (GMP_NUMB_BITS - GMP_NAIL_BITS + sc)))) & GMP_NUMB_MASK;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if BITS_PER_PART == 32 && LIMBS_PER_DOUBLE > 3
Packit 5c3484
  if (sc == 0)
Packit 5c3484
    {
Packit 5c3484
      int i;
Packit 5c3484
Packit 5c3484
      for (i = LIMBS_PER_DOUBLE - 1; i >= 0; i--)
Packit 5c3484
	{
Packit 5c3484
	  rp[i] = manh >> (BITS_PER_ULONG - GMP_NUMB_BITS);
Packit 5c3484
	  manh = ((manh << GMP_NUMB_BITS)
Packit 5c3484
		  | (manl >> (BITS_PER_ULONG - GMP_NUMB_BITS)));
Packit 5c3484
	  manl = manl << GMP_NUMB_BITS;
Packit 5c3484
	}
Packit 5c3484
      exp--;
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      int i;
Packit 5c3484
Packit 5c3484
      rp[LIMBS_PER_DOUBLE - 1] = (manh >> (GMP_LIMB_BITS - sc));
Packit 5c3484
      manh = (manh << sc) | (manl >> (GMP_LIMB_BITS - sc));
Packit 5c3484
      manl = (manl << sc);
Packit 5c3484
      for (i = LIMBS_PER_DOUBLE - 2; i >= 0; i--)
Packit 5c3484
	{
Packit 5c3484
	  rp[i] = manh >> (BITS_PER_ULONG - GMP_NUMB_BITS);
Packit 5c3484
	  manh = ((manh << GMP_NUMB_BITS)
Packit 5c3484
		  | (manl >> (BITS_PER_ULONG - GMP_NUMB_BITS)));
Packit 5c3484
	  manl = manl << GMP_NUMB_BITS;
Packit 5c3484
	}
Packit 5c3484
  }
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
  return exp;
Packit 5c3484
}