2022-01-01 18:54:23 +00:00
|
|
|
/* Copyright (C) 1995-2022 Free Software Foundation, Inc.
|
2006-01-28 00:15:15 +00:00
|
|
|
This file is part of the GNU C Library.
|
|
|
|
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2012-02-09 23:18:22 +00:00
|
|
|
License along with the GNU C Library; if not, see
|
Prefer https to http for gnu.org and fsf.org URLs
Also, change sources.redhat.com to sourceware.org.
This patch was automatically generated by running the following shell
script, which uses GNU sed, and which avoids modifying files imported
from upstream:
sed -ri '
s,(http|ftp)(://(.*\.)?(gnu|fsf|sourceware)\.org($|[^.]|\.[^a-z])),https\2,g
s,(http|ftp)(://(.*\.)?)sources\.redhat\.com($|[^.]|\.[^a-z]),https\2sourceware.org\4,g
' \
$(find $(git ls-files) -prune -type f \
! -name '*.po' \
! -name 'ChangeLog*' \
! -path COPYING ! -path COPYING.LIB \
! -path manual/fdl-1.3.texi ! -path manual/lgpl-2.1.texi \
! -path manual/texinfo.tex ! -path scripts/config.guess \
! -path scripts/config.sub ! -path scripts/install-sh \
! -path scripts/mkinstalldirs ! -path scripts/move-if-change \
! -path INSTALL ! -path locale/programs/charmap-kw.h \
! -path po/libc.pot ! -path sysdeps/gnu/errlist.c \
! '(' -name configure \
-execdir test -f configure.ac -o -f configure.in ';' ')' \
! '(' -name preconfigure \
-execdir test -f preconfigure.ac ';' ')' \
-print)
and then by running 'make dist-prepare' to regenerate files built
from the altered files, and then executing the following to cleanup:
chmod a+x sysdeps/unix/sysv/linux/riscv/configure
# Omit irrelevant whitespace and comment-only changes,
# perhaps from a slightly-different Autoconf version.
git checkout -f \
sysdeps/csky/configure \
sysdeps/hppa/configure \
sysdeps/riscv/configure \
sysdeps/unix/sysv/linux/csky/configure
# Omit changes that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/powerpc/powerpc64/ppc-mcount.S: trailing lines
git checkout -f \
sysdeps/powerpc/powerpc64/ppc-mcount.S \
sysdeps/unix/sysv/linux/s390/s390-64/syscall.S
# Omit change that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S: last line does not end in newline
git checkout -f sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S
2019-09-07 05:40:42 +00:00
|
|
|
<https://www.gnu.org/licenses/>. */
|
2006-01-28 00:15:15 +00:00
|
|
|
|
|
|
|
#include "gmp.h"
|
|
|
|
#include "gmp-impl.h"
|
|
|
|
#include "longlong.h"
|
|
|
|
#include <ieee754.h>
|
|
|
|
#include <float.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
/* Convert a `long double' in IBM extended format to a multi-precision
|
|
|
|
integer representing the significand scaled up by its number of
|
|
|
|
bits (106 for long double) and an integral power of two (MPN
|
|
|
|
frexpl). */
|
|
|
|
|
2016-02-29 19:27:36 +00:00
|
|
|
|
|
|
|
/* When signs differ, the actual value is the difference between the
|
|
|
|
significant double and the less significant double. Sometimes a
|
|
|
|
bit can be lost when we borrow from the significant mantissa. */
|
|
|
|
#define EXTRA_INTERNAL_PRECISION (7)
|
|
|
|
|
2006-01-28 00:15:15 +00:00
|
|
|
mp_size_t
|
|
|
|
__mpn_extract_long_double (mp_ptr res_ptr, mp_size_t size,
|
|
|
|
int *expt, int *is_neg,
|
|
|
|
long double value)
|
|
|
|
{
|
|
|
|
union ibm_extended_long_double u;
|
|
|
|
unsigned long long hi, lo;
|
|
|
|
int ediff;
|
2013-08-17 08:49:44 +00:00
|
|
|
|
2013-08-17 08:42:56 +00:00
|
|
|
u.ld = value;
|
2006-01-28 00:15:15 +00:00
|
|
|
|
2013-08-17 08:42:56 +00:00
|
|
|
*is_neg = u.d[0].ieee.negative;
|
|
|
|
*expt = (int) u.d[0].ieee.exponent - IEEE754_DOUBLE_BIAS;
|
2006-01-28 00:15:15 +00:00
|
|
|
|
2013-08-17 08:42:56 +00:00
|
|
|
lo = ((long long) u.d[1].ieee.mantissa0 << 32) | u.d[1].ieee.mantissa1;
|
|
|
|
hi = ((long long) u.d[0].ieee.mantissa0 << 32) | u.d[0].ieee.mantissa1;
|
2013-08-17 08:49:44 +00:00
|
|
|
|
2016-02-29 19:27:36 +00:00
|
|
|
/* Hold 7 extra bits of precision in the mantissa. This allows
|
|
|
|
the normalizing shifts below to prevent losing precision when
|
|
|
|
the signs differ and the exponents are sufficiently far apart. */
|
|
|
|
lo <<= EXTRA_INTERNAL_PRECISION;
|
|
|
|
|
2013-08-17 08:49:44 +00:00
|
|
|
/* If the lower double is not a denormal or zero then set the hidden
|
2006-01-28 00:15:15 +00:00
|
|
|
53rd bit. */
|
2013-08-17 08:49:44 +00:00
|
|
|
if (u.d[1].ieee.exponent != 0)
|
2016-02-29 19:27:36 +00:00
|
|
|
lo |= 1ULL << (52 + EXTRA_INTERNAL_PRECISION);
|
2013-08-17 08:49:44 +00:00
|
|
|
else
|
|
|
|
lo = lo << 1;
|
2006-01-28 00:15:15 +00:00
|
|
|
|
2013-08-17 08:49:44 +00:00
|
|
|
/* The lower double is normalized separately from the upper. We may
|
|
|
|
need to adjust the lower manitissa to reflect this. */
|
|
|
|
ediff = u.d[0].ieee.exponent - u.d[1].ieee.exponent - 53;
|
|
|
|
if (ediff > 0)
|
|
|
|
{
|
|
|
|
if (ediff < 64)
|
|
|
|
lo = lo >> ediff;
|
|
|
|
else
|
|
|
|
lo = 0;
|
2006-01-28 00:15:15 +00:00
|
|
|
}
|
2013-08-17 08:49:44 +00:00
|
|
|
else if (ediff < 0)
|
|
|
|
lo = lo << -ediff;
|
|
|
|
|
2006-01-28 00:15:15 +00:00
|
|
|
/* The high double may be rounded and the low double reflects the
|
|
|
|
difference between the long double and the rounded high double
|
|
|
|
value. This is indicated by a differnce between the signs of the
|
|
|
|
high and low doubles. */
|
2013-08-17 08:49:44 +00:00
|
|
|
if (u.d[0].ieee.negative != u.d[1].ieee.negative
|
|
|
|
&& lo != 0)
|
2006-01-28 00:15:15 +00:00
|
|
|
{
|
2016-02-29 19:27:36 +00:00
|
|
|
lo = (1ULL << (53 + EXTRA_INTERNAL_PRECISION)) - lo;
|
2013-08-17 08:49:44 +00:00
|
|
|
if (hi == 0)
|
2006-01-28 00:15:15 +00:00
|
|
|
{
|
|
|
|
/* we have a borrow from the hidden bit, so shift left 1. */
|
2016-02-29 19:27:36 +00:00
|
|
|
hi = 0x000ffffffffffffeLL | (lo >> (52 + EXTRA_INTERNAL_PRECISION));
|
|
|
|
lo = 0x0fffffffffffffffLL & (lo << 1);
|
2006-01-28 00:15:15 +00:00
|
|
|
(*expt)--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
hi--;
|
|
|
|
}
|
|
|
|
#if BITS_PER_MP_LIMB == 32
|
|
|
|
/* Combine the mantissas to be contiguous. */
|
2016-02-29 19:27:36 +00:00
|
|
|
res_ptr[0] = lo >> EXTRA_INTERNAL_PRECISION;
|
|
|
|
res_ptr[1] = (hi << (53 - 32)) | (lo >> (32 + EXTRA_INTERNAL_PRECISION));
|
2006-01-28 00:15:15 +00:00
|
|
|
res_ptr[2] = hi >> 11;
|
|
|
|
res_ptr[3] = hi >> (32 + 11);
|
|
|
|
#define N 4
|
|
|
|
#elif BITS_PER_MP_LIMB == 64
|
|
|
|
/* Combine the two mantissas to be contiguous. */
|
2016-02-29 19:27:36 +00:00
|
|
|
res_ptr[0] = (hi << 53) | (lo >> EXTRA_INTERNAL_PRECISION);
|
2006-01-28 00:15:15 +00:00
|
|
|
res_ptr[1] = hi >> 11;
|
|
|
|
#define N 2
|
|
|
|
#else
|
|
|
|
#error "mp_limb size " BITS_PER_MP_LIMB "not accounted for"
|
|
|
|
#endif
|
|
|
|
/* The format does not fill the last limb. There are some zeros. */
|
|
|
|
#define NUM_LEADING_ZEROS (BITS_PER_MP_LIMB \
|
|
|
|
- (LDBL_MANT_DIG - ((N - 1) * BITS_PER_MP_LIMB)))
|
|
|
|
|
2013-08-17 08:42:56 +00:00
|
|
|
if (u.d[0].ieee.exponent == 0)
|
2006-01-28 00:15:15 +00:00
|
|
|
{
|
|
|
|
/* A biased exponent of zero is a special case.
|
|
|
|
Either it is a zero or it is a denormal number. */
|
|
|
|
if (res_ptr[0] == 0 && res_ptr[1] == 0
|
|
|
|
&& res_ptr[N - 2] == 0 && res_ptr[N - 1] == 0) /* Assumes N<=4. */
|
|
|
|
/* It's zero. */
|
|
|
|
*expt = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* It is a denormal number, meaning it has no implicit leading
|
2012-04-03 16:38:46 +00:00
|
|
|
one bit, and its exponent is in fact the format minimum. We
|
|
|
|
use DBL_MIN_EXP instead of LDBL_MIN_EXP below because the
|
|
|
|
latter describes the properties of both parts together, but
|
|
|
|
the exponent is computed from the high part only. */
|
2006-01-28 00:15:15 +00:00
|
|
|
int cnt;
|
|
|
|
|
|
|
|
#if N == 2
|
|
|
|
if (res_ptr[N - 1] != 0)
|
|
|
|
{
|
|
|
|
count_leading_zeros (cnt, res_ptr[N - 1]);
|
|
|
|
cnt -= NUM_LEADING_ZEROS;
|
|
|
|
res_ptr[N - 1] = res_ptr[N - 1] << cnt
|
|
|
|
| (res_ptr[0] >> (BITS_PER_MP_LIMB - cnt));
|
|
|
|
res_ptr[0] <<= cnt;
|
2012-04-03 16:38:46 +00:00
|
|
|
*expt = DBL_MIN_EXP - 1 - cnt;
|
2006-01-28 00:15:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count_leading_zeros (cnt, res_ptr[0]);
|
|
|
|
if (cnt >= NUM_LEADING_ZEROS)
|
|
|
|
{
|
|
|
|
res_ptr[N - 1] = res_ptr[0] << (cnt - NUM_LEADING_ZEROS);
|
|
|
|
res_ptr[0] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
res_ptr[N - 1] = res_ptr[0] >> (NUM_LEADING_ZEROS - cnt);
|
|
|
|
res_ptr[0] <<= BITS_PER_MP_LIMB - (NUM_LEADING_ZEROS - cnt);
|
|
|
|
}
|
2012-04-03 16:38:46 +00:00
|
|
|
*expt = DBL_MIN_EXP - 1
|
2006-01-28 00:15:15 +00:00
|
|
|
- (BITS_PER_MP_LIMB - NUM_LEADING_ZEROS) - cnt;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int j, k, l;
|
|
|
|
|
|
|
|
for (j = N - 1; j > 0; j--)
|
|
|
|
if (res_ptr[j] != 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
count_leading_zeros (cnt, res_ptr[j]);
|
|
|
|
cnt -= NUM_LEADING_ZEROS;
|
|
|
|
l = N - 1 - j;
|
|
|
|
if (cnt < 0)
|
|
|
|
{
|
|
|
|
cnt += BITS_PER_MP_LIMB;
|
|
|
|
l--;
|
|
|
|
}
|
|
|
|
if (!cnt)
|
|
|
|
for (k = N - 1; k >= l; k--)
|
|
|
|
res_ptr[k] = res_ptr[k-l];
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (k = N - 1; k > l; k--)
|
|
|
|
res_ptr[k] = res_ptr[k-l] << cnt
|
|
|
|
| res_ptr[k-l-1] >> (BITS_PER_MP_LIMB - cnt);
|
|
|
|
res_ptr[k--] = res_ptr[0] << cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; k >= 0; k--)
|
|
|
|
res_ptr[k] = 0;
|
2012-04-03 16:38:46 +00:00
|
|
|
*expt = DBL_MIN_EXP - 1 - l * BITS_PER_MP_LIMB - cnt;
|
2006-01-28 00:15:15 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/* Add the implicit leading one bit for a normalized number. */
|
|
|
|
res_ptr[N - 1] |= (mp_limb_t) 1 << (LDBL_MANT_DIG - 1
|
|
|
|
- ((N - 1) * BITS_PER_MP_LIMB));
|
|
|
|
|
|
|
|
return N;
|
|
|
|
}
|