aboutsummaryrefslogtreecommitdiff
path: root/gcc/real.c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2013-11-20 14:34:49 +0000
committerJoseph Myers <jsm28@gcc.gnu.org>2013-11-20 14:34:49 +0000
commit547101fb67fb77fb069acd04669e18f6d4684c9f (patch)
tree64d27856340cb565d13242792a5eae7e1907b9f4 /gcc/real.c
parent74e25e34f85cc0a274cc82fd572ea62f619f8ccf (diff)
downloadgcc-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.c104
1 files changed, 36 insertions, 68 deletions
diff --git a/gcc/real.c b/gcc/real.c
index b59be66..82f3ba6 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -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;