From ee6ff319272d415b5c36d7f45e6e08e8273d6b62 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Oct 2002 01:01:12 -0700 Subject: [PATCH] real.h (SIGNIFICAND_BITS): Add one more word. * real.h (SIGNIFICAND_BITS): Add one more word. (CONST_DOUBLE_FORMAT): Accomodate 6 words. * real.c (times_pten): New. (real_to_decimal, real_from_string): Use it. (sticky_rshift_significand): Use & to find modulus. (rshift_significand, lshift_significand): Likewise. (do_divide): Apply sticky bit after normalization. (real_to_decimal, real_to_hexadecimal): Fix sign of Inf and NaN. From-SVN: r57811 --- gcc/ChangeLog | 15 +++++++-- gcc/real.c | 87 +++++++++++++++++++++++++++++---------------------- gcc/real.h | 8 +++-- 3 files changed, 68 insertions(+), 42 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 573d75ff428..e0817795ab7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2002-10-04 Richard Henderson + + * real.h (SIGNIFICAND_BITS): Add one more word. + (CONST_DOUBLE_FORMAT): Accomodate 6 words. + * real.c (times_pten): New. + (real_to_decimal, real_from_string): Use it. + (sticky_rshift_significand): Use & to find modulus. + (rshift_significand, lshift_significand): Likewise. + (do_divide): Apply sticky bit after normalization. + (real_to_decimal, real_to_hexadecimal): Fix sign of Inf and NaN. + 2002-10-03 Andreas Jaeger * gengtype.c (adjust_field_rtx_def): Cast variables of type size_t @@ -205,7 +216,7 @@ Wed Oct 2 17:01:36 CEST 2002 Jan Hubicka for TLS debug info to !DECL_EXTERNAL. 2002-10-01 Matt Thomas - Jason Thorpe + Jason Thorpe * config.gcc (vax-*-netbsdelf*): Enable configuration. * config/elfos.h (PCC_BITFIELD_TYPE_MATTERS): Define only @@ -322,7 +333,7 @@ Wed Oct 2 17:01:36 CEST 2002 Jan Hubicka * config/xtensa/xtensa.h (REG_CLASS_NAMES, REG_CLASS_CONTENTS): Add new RL_REGS register class. (PREFERRED_RELOAD_CLASS, PREFERRED_OUTPUT_RELOAD_CLASS): - Call xtensa_preferred_reload_class for both input and output reloads. + Call xtensa_preferred_reload_class for both input and output reloads. * config/xtensa/xtensa.c (xtensa_regno_to_class): Use new RL_REGS class. (xtensa_preferred_reload_class): Handle output reloads; use RL_REGS instead of either AR_REGS or GR_REGS classes. diff --git a/gcc/real.c b/gcc/real.c index 4ce60d9ad16..075da40f78c 100644 --- a/gcc/real.c +++ b/gcc/real.c @@ -53,10 +53,17 @@ In addition, E must be large enough to hold the smallest supported denormal number in a normalized form. - Both of these requirements are easily satisfied. The largest - target significand is 113 bits; we store 128. The smallest + 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 29. + Note that the decimal string conversion routines are sensitive to + rounding error. 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. + Target floating point models that use base 16 instead of base 2 (i.e. IBM 370), are handled during round_for_format, in which we canonicalize the exponent to be a multiple of 4 (log2(16)), and @@ -119,6 +126,7 @@ static void do_fix_trunc PARAMS ((REAL_VALUE_TYPE *, static const REAL_VALUE_TYPE * ten_to_ptwo PARAMS ((int)); static const REAL_VALUE_TYPE * real_digit PARAMS ((int)); +static void times_pten PARAMS ((REAL_VALUE_TYPE *, int)); static void round_for_format PARAMS ((const struct real_format *, REAL_VALUE_TYPE *)); @@ -186,7 +194,7 @@ sticky_rshift_significand (r, a, n) { for (i = 0, ofs = n / HOST_BITS_PER_LONG; i < ofs; ++i) sticky |= a->sig[i]; - n -= ofs * HOST_BITS_PER_LONG; + n &= HOST_BITS_PER_LONG - 1; } if (n != 0) @@ -222,7 +230,7 @@ rshift_significand (r, a, n) { unsigned int i, ofs = n / HOST_BITS_PER_LONG; - n -= ofs * HOST_BITS_PER_LONG; + n &= HOST_BITS_PER_LONG - 1; if (n != 0) { for (i = 0; i < SIGSZ; ++i) @@ -253,7 +261,7 @@ lshift_significand (r, a, n) { unsigned int i, ofs = n / HOST_BITS_PER_LONG; - n -= ofs * HOST_BITS_PER_LONG; + n &= HOST_BITS_PER_LONG - 1; if (n == 0) { for (i = 0; ofs + i < SIGSZ; ++i) @@ -888,10 +896,10 @@ do_divide (r, a, b) rr->exp = exp; inexact = div_significands (rr, a, b); - rr->sig[0] |= inexact; /* Re-normalize the result. */ normalize (rr); + rr->sig[0] |= inexact; if (rr != r) *r = t; @@ -1416,11 +1424,11 @@ real_to_decimal (str, r_orig, digits) case rvc_normal: break; case rvc_inf: - strcpy (str, (r.sign ? "+Inf" : "-Inf")); + strcpy (str, (r.sign ? "-Inf" : "+Inf")); return; case rvc_nan: /* ??? Print the significand as well, if not canonical? */ - strcpy (str, (r.sign ? "+NaN" : "-NaN")); + strcpy (str, (r.sign ? "-NaN" : "+NaN")); return; default: abort (); @@ -1441,21 +1449,7 @@ real_to_decimal (str, r_orig, digits) dec_exp = r.exp * M_LOG10_2; /* Scale the number such that it is in [1, 10). */ - if (dec_exp > 0) - { - int i; - for (i = EXP_BITS - 1; i >= 0; --i) - if (dec_exp & (1 << i)) - do_divide (&r, &r, ten_to_ptwo (i)); - } - else if (dec_exp < 0) - { - int i, pos_exp = -(--dec_exp); - - for (i = EXP_BITS - 1; i >= 0; --i) - if (pos_exp & (1 << i)) - do_multiply (&r, &r, ten_to_ptwo (i)); - } + times_pten (&r, (dec_exp > 0 ? -dec_exp : -(--dec_exp))); /* Assert that the number is in the proper range. Round-off can prevent the above from working exactly. */ @@ -1545,11 +1539,11 @@ real_to_hexadecimal (str, r, digits) case rvc_normal: break; case rvc_inf: - strcpy (str, (r->sign ? "+Inf" : "-Inf")); + strcpy (str, (r->sign ? "-Inf" : "+Inf")); return; case rvc_nan: /* ??? Print the significand as well, if not canonical? */ - strcpy (str, (r->sign ? "+NaN" : "-NaN")); + strcpy (str, (r->sign ? "-NaN" : "+NaN")); return; default: abort (); @@ -1755,19 +1749,8 @@ real_from_string (r, str) exp += d; } - if (exp < 0) - { - exp = -exp; - for (d = 0; d < EXP_BITS; ++d) - if (exp & (1 << d)) - do_divide (r, r, ten_to_ptwo (d)); - } - else if (exp > 0) - { - for (d = 0; d < EXP_BITS; ++d) - if (exp & (1 << d)) - do_multiply (r, r, ten_to_ptwo (d)); - } + if (exp) + times_pten (r, exp); } r->sign = sign; @@ -1900,6 +1883,34 @@ real_digit (n) return &num[n]; } +/* Multiply R by 10**EXP. */ + +static void +times_pten (r, exp) + REAL_VALUE_TYPE *r; + int exp; +{ + REAL_VALUE_TYPE pten, *rr; + bool negative = (exp < 0); + int i; + + if (negative) + { + exp = -exp; + pten = *real_digit (1); + rr = &pten; + } + else + rr = r; + + for (i = 0; exp > 0; ++i, exp >>= 1) + if (exp & 1) + do_multiply (rr, rr, ten_to_ptwo (i)); + + if (negative) + do_divide (r, r, &pten); +} + /* Fills R with +Inf. */ void diff --git a/gcc/real.h b/gcc/real.h index 900317048f2..fc84a109281 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -34,7 +34,7 @@ enum real_value_class { rvc_nan }; -#define SIGNIFICAND_BITS 128 +#define SIGNIFICAND_BITS (128 + HOST_BITS_PER_LONG) #define EXP_BITS (32 - 3) #define MAX_EXP ((1 << (EXP_BITS - 1)) - 1) #define SIGSZ (SIGNIFICAND_BITS / HOST_BITS_PER_LONG) @@ -88,7 +88,11 @@ extern char test_real_width # if REAL_WIDTH == 5 # define CONST_DOUBLE_FORMAT "wwwww" # else - #error "REAL_WIDTH > 5 not supported" +# if REAL_WIDTH == 6 +# define CONST_DOUBLE_FORMAT "wwwwww" +# else + #error "REAL_WIDTH > 6 not supported" +# endif # endif # endif # endif -- 2.30.2