diff options
Diffstat (limited to 'Build/source/libs/mpfr/mpfr-src/src/set_d64.c')
-rw-r--r-- | Build/source/libs/mpfr/mpfr-src/src/set_d64.c | 108 |
1 files changed, 87 insertions, 21 deletions
diff --git a/Build/source/libs/mpfr/mpfr-src/src/set_d64.c b/Build/source/libs/mpfr/mpfr-src/src/set_d64.c index e7470499630..41c2e7da585 100644 --- a/Build/source/libs/mpfr/mpfr-src/src/set_d64.c +++ b/Build/source/libs/mpfr/mpfr-src/src/set_d64.c @@ -1,11 +1,11 @@ /* mpfr_set_decimal64 -- convert an IEEE 754-2008 decimal64 float to a multiple precision floating-point number -See https://gcc.gnu.org/ml/gcc/2006-06/msg00691.html, +See https://gcc.gnu.org/legacy-ml/gcc/2006-06/msg00691.html, https://gcc.gnu.org/onlinedocs/gcc/Decimal-Float.html, and TR 24732 <http://www.open-std.org/jtc1/sc22/wg14/www/projects#24732>. -Copyright 2006-2019 Free Software Foundation, Inc. +Copyright 2006-2020 Free Software Foundation, Inc. Contributed by the AriC and Caramba projects, INRIA. This file is part of the GNU MPFR Library. @@ -30,7 +30,7 @@ https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., #ifdef MPFR_WANT_DECIMAL_FLOATS -#ifdef DPD_FORMAT +#ifdef DECIMAL_DPD_FORMAT /* conversion 10-bits to 3 digits */ static unsigned int T[1024] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 80, 81, 800, 801, 880, 881, 10, 11, 12, 13, @@ -102,7 +102,8 @@ static unsigned int T[1024] = { 774, 775, 776, 777, 778, 779, 796, 797, 976, 977, 998, 999 }; #endif -#if _MPFR_IEEE_FLOATS +#if _MPFR_IEEE_FLOATS && !defined(DECIMAL_GENERIC_CODE) + /* Convert d to a decimal string (one-to-one correspondence, no rounding). The string s needs to have at least 25 characters (with the final '\0'): * 1 for the sign '-' @@ -119,16 +120,42 @@ decimal64_to_string (char *s, _Decimal64 d) char *t; unsigned int Gh; /* most 5 significant bits from combination field */ int exp; /* exponent */ - mp_limb_t rp[2]; - mp_size_t rn = 2; unsigned int i; -#ifdef DPD_FORMAT + +#ifdef DECIMAL_DPD_FORMAT unsigned int d0, d1, d2, d3, d4, d5; +#else /* BID */ +#if GMP_NUMB_BITS >= 64 + mp_limb_t rp[2]; +#else + unsigned long rp[2]; /* rp[0] and rp[1] should contain at least 32 bits */ +#endif +#define NLIMBS (64 / GMP_NUMB_BITS) + mp_limb_t sp[NLIMBS]; + mp_size_t sn; #endif + /* end of declarations */ + + /* Memory representation of the _Decimal64 argument. */ + MPFR_LOG_MSG (("d = { %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X }\n", + ((unsigned char *) &d)[0], + ((unsigned char *) &d)[1], + ((unsigned char *) &d)[2], + ((unsigned char *) &d)[3], + ((unsigned char *) &d)[4], + ((unsigned char *) &d)[5], + ((unsigned char *) &d)[6], + ((unsigned char *) &d)[7])); + /* now convert BID or DPD to string */ y.d64 = d; x.d = y.d; + MPFR_LOG_MSG (("x = { .sig = %u, .exp = %u, " + ".manh = 0x%05lX = %lu, .manl = 0x%08lX = %lu }\n", + (unsigned int) x.s.sig, (unsigned int) x.s.exp, + (unsigned long) x.s.manh, (unsigned long) x.s.manh, + (unsigned long) x.s.manl, (unsigned long) x.s.manl)); Gh = x.s.exp >> 6; if (Gh == 31) { @@ -147,16 +174,23 @@ decimal64_to_string (char *s, _Decimal64 d) if (x.s.sig) *t++ = '-'; -#ifdef DPD_FORMAT + /* both the decimal64 DPD and BID encodings consist of: + * a sign bit of 1 bit + * a combination field of 13=5+8 bits + * a trailing significand field of 50 bits + */ +#ifdef DECIMAL_DPD_FORMAT + /* the most significant 5 bits of the combination field give the first digit + of the significand, and leading bits of the biased exponent (0, 1, 2). */ if (Gh < 24) { exp = (x.s.exp >> 1) & 768; - d0 = Gh & 7; + d0 = Gh & 7; /* first digit is in 0..7 */ } else { exp = (x.s.exp & 384) << 1; - d0 = 8 | (Gh & 1); + d0 = 8 | (Gh & 1); /* first digit is 8 or 9 */ } exp |= (x.s.exp & 63) << 2; exp |= x.s.manh >> 18; @@ -172,6 +206,8 @@ decimal64_to_string (char *s, _Decimal64 d) t[i] = '0'; t += 16; #else /* BID */ + /* IEEE 754-2008 specifies that if the decoded significand exceeds the + maximum, i.e. here if it is >= 10^16, then the value is zero. */ if (Gh < 24) { /* the biased exponent E is formed from G[0] to G[9] and the @@ -191,30 +227,56 @@ decimal64_to_string (char *s, _Decimal64 d) rp[1] &= 524287; /* 2^19-1: cancel G[11] */ rp[1] |= 2097152; /* add 2^21 */ } -#if GMP_NUMB_BITS >= 54 - rp[0] |= rp[1] << 32; - rn = 1; + /* now convert {rp, 2} to {sp, NLIMBS} */ +#if GMP_NUMB_BITS >= 64 + sp[0] = MPFR_LIMB(rp[0]) | MPFR_LIMB_LSHIFT(rp[1],32); +#elif GMP_NUMB_BITS == 32 + sp[0] = rp[0]; + sp[1] = rp[1]; +#elif GMP_NUMB_BITS == 16 + sp[0] = MPFR_LIMB(rp[0]); + sp[1] = MPFR_LIMB(rp[0] >> 16); + sp[2] = MPFR_LIMB(rp[1]); + sp[3] = MPFR_LIMB(rp[1] >> 16); +#elif GMP_NUMB_BITS == 8 + sp[0] = MPFR_LIMB(rp[0]); + sp[1] = MPFR_LIMB(rp[0] >> 8); + sp[2] = MPFR_LIMB(rp[0] >> 16); + sp[3] = MPFR_LIMB(rp[0] >> 24); + sp[4] = MPFR_LIMB(rp[1]); + sp[5] = MPFR_LIMB(rp[1] >> 8); + sp[6] = MPFR_LIMB(rp[1] >> 16); + sp[7] = MPFR_LIMB(rp[1] >> 24); +#else +#error "GMP_NUMB_BITS should be 8, 16, 32, or >= 64" #endif - while (rn > 0 && rp[rn - 1] == 0) - rn --; - if (rn == 0) + sn = NLIMBS; + while (sn > 0 && sp[sn - 1] == 0) + sn --; + if (sn == 0) { + zero: *t = 0; i = 1; } else { - i = mpn_get_str ((unsigned char*)t, 10, rp, rn); + i = mpn_get_str ((unsigned char*) t, 10, sp, sn); + if (i > 16) /* non-canonical encoding: return zero */ + goto zero; } + /* convert the values from mpn_get_str (0, 1, ..., 9) to digits: */ while (i-- > 0) *t++ += '0'; #endif /* DPD or BID */ - exp -= 398; /* unbiased exponent */ + exp -= 398; /* unbiased exponent: -398 = emin - (p-1) where + emin = 1-emax = 1-384 = -383 and p=16 */ sprintf (t, "E%d", exp); } -#else -/* portable version */ + +#else /* portable version */ + #ifndef DEC64_MAX # define DEC64_MAX 9.999999999999999E384dd #endif @@ -412,8 +474,11 @@ decimal64_to_string (char *s, _Decimal64 d) else *s = '\0'; } -#endif /* _MPFR_IEEE_FLOATS */ +#endif /* definition of decimal64_to_string (DPD, BID, or portable) */ + +/* the IEEE754-2008 decimal64 format has 16 digits, with emax=384, + emin=1-emax=-383 */ int mpfr_set_decimal64 (mpfr_ptr r, _Decimal64 d, mpfr_rnd_t rnd_mode) { @@ -425,6 +490,7 @@ mpfr_set_decimal64 (mpfr_ptr r, _Decimal64 d, mpfr_rnd_t rnd_mode) 1 character for terminating \0. */ decimal64_to_string (s, d); + MPFR_LOG_MSG (("string: %s\n", s)); return mpfr_strtofr (r, s, NULL, 10, rnd_mode); } |