Commit 55fc9243 by Jakub Jelinek Committed by Jakub Jelinek

re PR libfortran/24685 (real(16) formatted input is broken for huge values…

re PR libfortran/24685 (real(16) formatted input is broken for huge values (gfortran.dg/default_format_2.f90))

	PR libgfortran/24685
	* io/write.c (MIN_FIELD_WIDTH, STR, STR1): Define.
	(output_float): Increase buffer sizes for IEEE quad and IBM extended
	long double.
	(write_real): Output REAL(16) as 1PG43.34E4 rather than 1PG40.31E4.

From-SVN: r112819
parent 9f889fcf
2006-04-10 Jakub Jelinek <jakub@redhat.com>
PR libgfortran/24685
* io/write.c (MIN_FIELD_WIDTH, STR, STR1): Define.
(output_float): Increase buffer sizes for IEEE quad and IBM extended
long double.
(write_real): Output REAL(16) as 1PG43.34E4 rather than 1PG40.31E4.
2006-04-07 Jerry DeLisle <jvdelisle@gcc.gnu.org> 2006-04-07 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libgfortran/26890 PR libgfortran/26890
......
/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. /* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Contributed by Andy Vaught Contributed by Andy Vaught
Namelist output contibuted by Paul Thomas Namelist output contibuted by Paul Thomas
...@@ -376,8 +376,15 @@ calculate_G_format (st_parameter_dt *dtp, const fnode *f, ...@@ -376,8 +376,15 @@ calculate_G_format (st_parameter_dt *dtp, const fnode *f,
static void static void
output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value) output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value)
{ {
#if defined(HAVE_GFC_REAL_16) && __LDBL_DIG__ > 18
# define MIN_FIELD_WIDTH 46
#else
# define MIN_FIELD_WIDTH 31
#endif
#define STR(x) STR1(x)
#define STR1(x) #x
/* This must be large enough to accurately hold any value. */ /* This must be large enough to accurately hold any value. */
char buffer[32]; char buffer[MIN_FIELD_WIDTH+1];
char *out; char *out;
char *digits; char *digits;
int e; int e;
...@@ -413,8 +420,8 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value) ...@@ -413,8 +420,8 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value)
internal_error (&dtp->common, "Unspecified precision"); internal_error (&dtp->common, "Unspecified precision");
/* Use sprintf to print the number in the format +D.DDDDe+ddd /* Use sprintf to print the number in the format +D.DDDDe+ddd
For an N digit exponent, this gives us (32-6)-N digits after the For an N digit exponent, this gives us (MIN_FIELD_WIDTH-5)-N digits
decimal point, plus another one before the decimal point. */ after the decimal point, plus another one before the decimal point. */
sign = calculate_sign (dtp, value < 0.0); sign = calculate_sign (dtp, value < 0.0);
if (value < 0) if (value < 0)
value = -value; value = -value;
...@@ -439,7 +446,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value) ...@@ -439,7 +446,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value)
|| ((ft == FMT_D || ft == FMT_E) && dtp->u.p.scale_factor != 0)) || ((ft == FMT_D || ft == FMT_E) && dtp->u.p.scale_factor != 0))
{ {
/* Always convert at full precision to avoid double rounding. */ /* Always convert at full precision to avoid double rounding. */
ndigits = 27 - edigits; ndigits = MIN_FIELD_WIDTH - 4 - edigits;
} }
else else
{ {
...@@ -449,8 +456,8 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value) ...@@ -449,8 +456,8 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value)
ndigits = d + 1; ndigits = d + 1;
else else
ndigits = d; ndigits = d;
if (ndigits > 27 - edigits) if (ndigits > MIN_FIELD_WIDTH - 4 - edigits)
ndigits = 27 - edigits; ndigits = MIN_FIELD_WIDTH - 4 - edigits;
} }
/* # The result will always contain a decimal point, even if no /* # The result will always contain a decimal point, even if no
...@@ -460,7 +467,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value) ...@@ -460,7 +467,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value)
* *
* + A sign (+ or -) always be placed before a number * + A sign (+ or -) always be placed before a number
* *
* 31 minimum field width * MIN_FIELD_WIDTH minimum field width
* *
* * (ndigits-1) is used as the precision * * (ndigits-1) is used as the precision
* *
...@@ -469,8 +476,8 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value) ...@@ -469,8 +476,8 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value)
* equal to the precision. The exponent always contains at least two * equal to the precision. The exponent always contains at least two
* digits; if the value is zero, the exponent is 00. * digits; if the value is zero, the exponent is 00.
*/ */
sprintf (buffer, "%+-#31.*" GFC_REAL_LARGEST_FORMAT "e", sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*"
ndigits - 1, value); GFC_REAL_LARGEST_FORMAT "e", ndigits - 1, value);
/* Check the resulting string has punctuation in the correct places. */ /* Check the resulting string has punctuation in the correct places. */
if (d != 0 && (buffer[2] != '.' || buffer[ndigits + 2] != 'e')) if (d != 0 && (buffer[2] != '.' || buffer[ndigits + 2] != 'e'))
...@@ -777,7 +784,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value) ...@@ -777,7 +784,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value)
edigits--; edigits--;
} }
#if HAVE_SNPRINTF #if HAVE_SNPRINTF
snprintf (buffer, 32, "%+0*d", edigits, e); snprintf (buffer, sizeof (buffer), "%+0*d", edigits, e);
#else #else
sprintf (buffer, "%+0*d", edigits, e); sprintf (buffer, "%+0*d", edigits, e);
#endif #endif
...@@ -790,6 +797,9 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value) ...@@ -790,6 +797,9 @@ output_float (st_parameter_dt *dtp, const fnode *f, GFC_REAL_LARGEST value)
memset( out , ' ' , nblanks ); memset( out , ' ' , nblanks );
dtp->u.p.no_leading_blank = 0; dtp->u.p.no_leading_blank = 0;
} }
#undef STR
#undef STR1
#undef MIN_FIELD_WIDTH
} }
...@@ -1352,7 +1362,7 @@ write_character (st_parameter_dt *dtp, const char *source, int length) ...@@ -1352,7 +1362,7 @@ write_character (st_parameter_dt *dtp, const char *source, int length)
/* Output a real number with default format. /* Output a real number with default format.
This is 1PG14.7E2 for REAL(4), 1PG23.15E3 for REAL(8), This is 1PG14.7E2 for REAL(4), 1PG23.15E3 for REAL(8),
1PG24.15E4 for REAL(10) and 1PG40.31E4 for REAL(16). */ 1PG28.19E4 for REAL(10) and 1PG43.34E4 for REAL(16). */
static void static void
write_real (st_parameter_dt *dtp, const char *source, int length) write_real (st_parameter_dt *dtp, const char *source, int length)
...@@ -1379,8 +1389,8 @@ write_real (st_parameter_dt *dtp, const char *source, int length) ...@@ -1379,8 +1389,8 @@ write_real (st_parameter_dt *dtp, const char *source, int length)
f.u.real.e = 4; f.u.real.e = 4;
break; break;
case 16: case 16:
f.u.real.w = 40; f.u.real.w = 43;
f.u.real.d = 31; f.u.real.d = 34;
f.u.real.e = 4; f.u.real.e = 4;
break; break;
default: default:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment