diff options
author | Janis Johnson <janis187@us.ibm.com> | 2009-09-17 17:07:24 +0000 |
---|---|---|
committer | Janis Johnson <janis@gcc.gnu.org> | 2009-09-17 17:07:24 +0000 |
commit | d2da4af2c7872e1d9892cc5b3792d10dd86782a4 (patch) | |
tree | 76332f90632195d93b999cee84b8426bd071c7d0 /gcc/real.c | |
parent | 51a0d6aa772829f49bc40564c92aa96e7a3cd910 (diff) | |
download | gcc-d2da4af2c7872e1d9892cc5b3792d10dd86782a4.zip gcc-d2da4af2c7872e1d9892cc5b3792d10dd86782a4.tar.gz gcc-d2da4af2c7872e1d9892cc5b3792d10dd86782a4.tar.bz2 |
re PR c/41049 (conversion from integer to decimal float loses trailing zeros)
gcc/
PR c/41049
* real.c decimal_from_integer, decimal_integer_string): New.
(real_from_integer): Use them as special case for decimal float.
* config/dfp-bit.c (_si_to_sd, _usi_to_sd): Use default rounding.
(_di_to_sd, _di_to_dd, _di_to_td, _udi_to_sd, _udi_to_dd, _udi_to_td):
Do not append zero after the decimal point in string to convert.
gcc/testsuite/
PR c/41049
* dfp/pr41049.c: New test.
From-SVN: r151806
Diffstat (limited to 'gcc/real.c')
-rw-r--r-- | gcc/real.c | 65 |
1 files changed, 64 insertions, 1 deletions
@@ -110,6 +110,9 @@ static int do_compare (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int); static void do_fix_trunc (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); static unsigned long rtd_divmod (REAL_VALUE_TYPE *, REAL_VALUE_TYPE *); +static void decimal_from_integer (REAL_VALUE_TYPE *); +static void decimal_integer_string (char *, const REAL_VALUE_TYPE *, + size_t); static const REAL_VALUE_TYPE * ten_to_ptwo (int); static const REAL_VALUE_TYPE * ten_to_mptwo (int); @@ -2168,10 +2171,70 @@ real_from_integer (REAL_VALUE_TYPE *r, enum machine_mode mode, normalize (r); } - if (mode != VOIDmode) + if (DECIMAL_FLOAT_MODE_P (mode)) + decimal_from_integer (r); + else if (mode != VOIDmode) real_convert (r, mode, r); } +/* Render R, an integral value, as a floating point constant with no + specified exponent. */ + +static void +decimal_integer_string (char *str, const REAL_VALUE_TYPE *r_orig, + size_t buf_size) +{ + int dec_exp, digit, digits; + REAL_VALUE_TYPE r, pten; + char *p; + bool sign; + + r = *r_orig; + + if (r.cl == rvc_zero) + { + strcpy (str, "0."); + return; + } + + sign = r.sign; + r.sign = 0; + + dec_exp = REAL_EXP (&r) * M_LOG10_2; + digits = dec_exp + 1; + gcc_assert ((digits + 2) < (int)buf_size); + + pten = *real_digit (1); + times_pten (&pten, dec_exp); + + p = str; + if (sign) + *p++ = '-'; + + digit = rtd_divmod (&r, &pten); + gcc_assert (digit >= 0 && digit <= 9); + *p++ = digit + '0'; + while (--digits > 0) + { + times_pten (&r, 1); + digit = rtd_divmod (&r, &pten); + *p++ = digit + '0'; + } + *p++ = '.'; + *p++ = '\0'; +} + +/* Convert a real with an integral value to decimal float. */ + +static void +decimal_from_integer (REAL_VALUE_TYPE *r) +{ + char str[256]; + + decimal_integer_string (str, r, sizeof (str) - 1); + decimal_real_from_string (r, str); +} + /* Returns 10**2**N. */ static const REAL_VALUE_TYPE * |