Blame extract-dbl.c

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