diff options
author | Joseph Myers <joseph@codesourcery.com> | 2013-11-20 14:34:49 +0000 |
---|---|---|
committer | Joseph Myers <jsm28@gcc.gnu.org> | 2013-11-20 14:34:49 +0000 |
commit | 547101fb67fb77fb069acd04669e18f6d4684c9f (patch) | |
tree | 64d27856340cb565d13242792a5eae7e1907b9f4 /gcc/real.c | |
parent | 74e25e34f85cc0a274cc82fd572ea62f619f8ccf (diff) | |
download | gcc-547101fb67fb77fb069acd04669e18f6d4684c9f.zip gcc-547101fb67fb77fb069acd04669e18f6d4684c9f.tar.gz gcc-547101fb67fb77fb069acd04669e18f6d4684c9f.tar.bz2 |
re PR middle-end/21718 (real.c rounding not perfect)
PR middle-end/21718
* real.c: Remove comment about decimal string conversion and
rounding errors.
(real_from_string): Use MPFR to convert nonzero decimal constant
to REAL_VALUE_TYPE.
testsuite:
* gcc.dg/float-exact-1.c: New test.
From-SVN: r205119
Diffstat (limited to 'gcc/real.c')
-rw-r--r-- | gcc/real.c | 104 |
1 files changed, 36 insertions, 68 deletions
@@ -57,14 +57,7 @@ Both of these requirements are easily satisfied. The largest target significand is 113 bits; we store at least 160. The smallest - denormal number fits in 17 exponent bits; we store 26. - - Note that the decimal string conversion routines are sensitive to - rounding errors. Since the raw arithmetic routines do not themselves - have guard digits or rounding, the computation of 10**exp can - accumulate more than a few digits of error. The previous incarnation - of real.c successfully used a 144-bit fraction; given the current - layout of REAL_VALUE_TYPE we're forced to expand to at least 160 bits. */ + denormal number fits in 17 exponent bits; we store 26. */ /* Used to classify two numbers simultaneously. */ @@ -2029,75 +2022,50 @@ real_from_string (REAL_VALUE_TYPE *r, const char *str) else { /* Decimal floating point. */ - const REAL_VALUE_TYPE *ten = ten_to_ptwo (0); - int d; + const char *cstr = str; + mpfr_t m; + bool inexact; - while (*str == '0') - str++; - while (ISDIGIT (*str)) + while (*cstr == '0') + cstr++; + if (*cstr == '.') { - d = *str++ - '0'; - do_multiply (r, r, ten); - if (d) - do_add (r, r, real_digit (d), 0); - } - if (*str == '.') - { - str++; - if (r->cl == rvc_zero) - { - while (*str == '0') - str++, exp--; - } - while (ISDIGIT (*str)) - { - d = *str++ - '0'; - do_multiply (r, r, ten); - if (d) - do_add (r, r, real_digit (d), 0); - exp--; - } + cstr++; + while (*cstr == '0') + cstr++; } /* If the mantissa is zero, ignore the exponent. */ - if (r->cl == rvc_zero) + if (!ISDIGIT (*cstr)) goto is_a_zero; - if (*str == 'e' || *str == 'E') + /* Nonzero value, possibly overflowing or underflowing. */ + mpfr_init2 (m, SIGNIFICAND_BITS); + inexact = mpfr_strtofr (m, str, NULL, 10, GMP_RNDZ); + /* The result should never be a NaN, and because the rounding is + toward zero should never be an infinity. */ + gcc_assert (!mpfr_nan_p (m) && !mpfr_inf_p (m)); + if (mpfr_zero_p (m) || mpfr_get_exp (m) < -MAX_EXP + 4) { - bool exp_neg = false; - - str++; - if (*str == '-') - { - exp_neg = true; - str++; - } - else if (*str == '+') - str++; - - d = 0; - while (ISDIGIT (*str)) - { - d *= 10; - d += *str - '0'; - if (d > MAX_EXP) - { - /* Overflowed the exponent. */ - if (exp_neg) - goto underflow; - else - goto overflow; - } - str++; - } - if (exp_neg) - d = -d; - exp += d; + mpfr_clear (m); + goto underflow; + } + else if (mpfr_get_exp (m) > MAX_EXP - 4) + { + mpfr_clear (m); + goto overflow; + } + else + { + real_from_mpfr (r, m, NULL_TREE, GMP_RNDZ); + /* 1 to 3 bits may have been shifted off (with a sticky bit) + because the hex digits used in real_from_mpfr did not + start with a digit 8 to f, but the exponent bounds above + should have avoided underflow or overflow. */ + gcc_assert (r->cl = rvc_normal); + /* Set a sticky bit if mpfr_strtofr was inexact. */ + r->sig[0] |= inexact; } - - if (exp) - times_pten (r, exp); } r->sign = sign; |