|
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 |
}
|