diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index 11202c34eb8..8a199fe2d15 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,25 @@ +2011-04-29 Jerry DeLisle + Janne Blomqvist + + PR libgfortran/48488 + PR libgfortran/48602 + PR libgfortran/48615 + PR libgfortran/48684 + PR libgfortran/48787 + * io/write.c (write_d, write_e, write_f, write_en, + write_es): Add precision compemsation parameter to call. + (set_fnode_default): Adjust default widths to assure + round trip on write and read. (write_real): Adjust call to write_float. + (write_real_g0): Calculate compensation for extra precision and adjust + call to write_float. + * io/write_float.def (output_float_FMT_G_): Use volatile rather than + asm volatile to avoid optimization issue. Correctly calculate the + number of blanks (nb) to be appended and simplify calculation logic. + (write_float): Increase MIN_FIELD_WIDTH by one to accomodate the new + default widths. Eliminate the code that attempted to reduce the + the precision used in later sprintf functions. Add call parameter to + compensate for extra precision. + 2011-04-20 Jim Meyering * intrinsics/move_alloc.c (move_alloc): Remove useless diff --git a/libgfortran/io/write.c b/libgfortran/io/write.c index 5338162bc6c..bf02ad8b1aa 100644 --- a/libgfortran/io/write.c +++ b/libgfortran/io/write.c @@ -1155,35 +1155,35 @@ write_z (st_parameter_dt *dtp, const fnode *f, const char *source, int len) void write_d (st_parameter_dt *dtp, const fnode *f, const char *p, int len) { - write_float (dtp, f, p, len); + write_float (dtp, f, p, len, 0); } void write_e (st_parameter_dt *dtp, const fnode *f, const char *p, int len) { - write_float (dtp, f, p, len); + write_float (dtp, f, p, len, 0); } void write_f (st_parameter_dt *dtp, const fnode *f, const char *p, int len) { - write_float (dtp, f, p, len); + write_float (dtp, f, p, len, 0); } void write_en (st_parameter_dt *dtp, const fnode *f, const char *p, int len) { - write_float (dtp, f, p, len); + write_float (dtp, f, p, len, 0); } void write_es (st_parameter_dt *dtp, const fnode *f, const char *p, int len) { - write_float (dtp, f, p, len); + write_float (dtp, f, p, len, 0); } @@ -1432,8 +1432,8 @@ set_fnode_default (st_parameter_dt *dtp, fnode *f, int length) switch (length) { case 4: - f->u.real.w = 15; - f->u.real.d = 8; + f->u.real.w = 16; + f->u.real.d = 9; f->u.real.e = 2; break; case 8: @@ -1442,13 +1442,13 @@ set_fnode_default (st_parameter_dt *dtp, fnode *f, int length) f->u.real.e = 3; break; case 10: - f->u.real.w = 29; - f->u.real.d = 20; + f->u.real.w = 30; + f->u.real.d = 21; f->u.real.e = 4; break; case 16: - f->u.real.w = 44; - f->u.real.d = 35; + f->u.real.w = 45; + f->u.real.d = 36; f->u.real.e = 4; break; default: @@ -1468,7 +1468,7 @@ write_real (st_parameter_dt *dtp, const char *source, int length) int org_scale = dtp->u.p.scale_factor; dtp->u.p.scale_factor = 1; set_fnode_default (dtp, &f, length); - write_float (dtp, &f, source , length); + write_float (dtp, &f, source , length, 1); dtp->u.p.scale_factor = org_scale; } @@ -1476,12 +1476,20 @@ write_real (st_parameter_dt *dtp, const char *source, int length) void write_real_g0 (st_parameter_dt *dtp, const char *source, int length, int d) { - fnode f ; + fnode f; + int comp_d; set_fnode_default (dtp, &f, length); if (d > 0) f.u.real.d = d; + + /* Compensate for extra digits when using scale factor, d is not + specified, and the magnitude is such that E editing is used. */ + if (dtp->u.p.scale_factor > 0 && d == 0) + comp_d = 1; + else + comp_d = 0; dtp->u.p.g0_no_blanks = 1; - write_float (dtp, &f, source , length); + write_float (dtp, &f, source , length, comp_d); dtp->u.p.g0_no_blanks = 0; } diff --git a/libgfortran/io/write_float.def b/libgfortran/io/write_float.def index 2bced6ffec4..2e2b4d87bf4 100644 --- a/libgfortran/io/write_float.def +++ b/libgfortran/io/write_float.def @@ -289,8 +289,9 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, } else if (nbefore + nafter < ndigits) { - ndigits = nbefore + nafter; - i = ndigits; + i = ndigits = nbefore + nafter; + if (d == 0 && digits[1] == '0') + goto skip; if (digits[i] >= rchar) { /* Propagate the carry. */ @@ -812,7 +813,8 @@ CALCULATE_EXP(16) static void \ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \ GFC_REAL_ ## x m, char *buffer, size_t size, \ - int sign_bit, bool zero_flag, int ndigits, int edigits) \ + int sign_bit, bool zero_flag, int ndigits, \ + int edigits, int comp_d) \ { \ int e = f->u.real.e;\ int d = f->u.real.d;\ @@ -850,7 +852,7 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \ { \ newf->format = FMT_E;\ newf->u.real.w = w;\ - newf->u.real.d = d;\ + newf->u.real.d = d - comp_d;\ newf->u.real.e = e;\ nb = 0;\ goto finish;\ @@ -864,11 +866,10 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \ \ while (low <= high)\ { \ - GFC_REAL_ ## x temp;\ + volatile GFC_REAL_ ## x temp;\ mid = (low + high) / 2;\ \ temp = (calculate_exp_ ## x (mid - 1) * (1 - r * rexp_d));\ - asm volatile ("" : "+m" (temp));\ \ if (m < temp)\ { \ @@ -894,22 +895,11 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \ }\ }\ \ - if (e > 4)\ - e = 4;\ - if (e < 0)\ - nb = 4;\ - else\ - nb = e + 2;\ -\ - nb = nb >= w ? 0 : nb;\ + nb = e <= 0 ? 4 : e + 2;\ + nb = nb >= w ? w - 1 : nb;\ newf->format = FMT_F;\ - newf->u.real.w = f->u.real.w - nb;\ -\ - if (m == 0.0)\ - newf->u.real.d = d - 1;\ - else\ - newf->u.real.d = - (mid - d - 1);\ -\ + newf->u.real.w = w - nb;\ + newf->u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\ dtp->u.p.scale_factor = 0;\ \ finish:\ @@ -931,7 +921,7 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \ gfc_char4_t *p4 = (gfc_char4_t *) p;\ memset4 (p4, pad, nb);\ }\ - else\ + else \ memset (p, pad, nb);\ }\ }\ @@ -1010,19 +1000,20 @@ __qmath_(quadmath_snprintf) (buffer, sizeof buffer, \ edigits);\ else \ output_float_FMT_G_ ## x (dtp, f, tmp, buffer, size, sign_bit, \ - zero_flag, ndigits, edigits);\ + zero_flag, ndigits, edigits, comp_d);\ }\ /* Output a real number according to its format. */ static void -write_float (st_parameter_dt *dtp, const fnode *f, const char *source, int len) +write_float (st_parameter_dt *dtp, const fnode *f, const char *source, \ + int len, int comp_d) { #if defined(HAVE_GFC_REAL_16) || __LDBL_DIG__ > 18 -# define MIN_FIELD_WIDTH 48 +# define MIN_FIELD_WIDTH 49 #else -# define MIN_FIELD_WIDTH 31 +# define MIN_FIELD_WIDTH 32 #endif #define STR(x) STR1(x) #define STR1(x) #x @@ -1039,23 +1030,8 @@ write_float (st_parameter_dt *dtp, const fnode *f, const char *source, int len) to handle the largest number of exponent digits expected. */ edigits=4; - if (f->format == FMT_F || f->format == FMT_EN || f->format == FMT_G - || ((f->format == FMT_D || f->format == FMT_E) - && dtp->u.p.scale_factor != 0)) - { - /* Always convert at full precision to avoid double rounding. */ - ndigits = MIN_FIELD_WIDTH - 4 - edigits; - } - else - { - /* The number of digits is known, so let printf do the rounding. */ - if (f->format == FMT_ES) - ndigits = f->u.real.d + 1; - else - ndigits = f->u.real.d; - if (ndigits > MIN_FIELD_WIDTH - 4 - edigits) - ndigits = MIN_FIELD_WIDTH - 4 - edigits; - } + /* Always convert at full precision to avoid double rounding. */ + ndigits = MIN_FIELD_WIDTH - 4 - edigits; switch (len) {