mirror of git://gcc.gnu.org/git/gcc.git
re PR libfortran/52434 (Insufficient number of digits in floating point formatting)
2012-03-15 Janne Blomqvist <jb@gcc.gnu.org>
PR libfortran/52434
PR libfortran/48878
PR libfortran/38199
* io/unit.c (get_internal_unit): Default to ROUND_UNSPECIFIED.
(init_units): Likewise.
* io/write_float.def (determine_precision): New function.
(output_float): Take into account buffer with %f format, no need
for our own rounding if unspecified or processor specified
rounding.
(DTOA): Simplify format string, add parameters.
(FDTOA): New macros similar to DTOA, but using %f format.
(OUTPUT_FLOAT_FMT_G): Stack allocate newf, determine correct
precision and fill buffer.
(EN_PREC): New macro.
(determine_en_precision): New function.
(WRITE_FLOAT): For G format, move buffer filling into
output_float_FMT_G, use FDTOA for F format.
(write_float): Increase buffer due to F format.
testsuite ChangeLog:
2012-03-15 Janne Blomqvist <jb@gcc.gnu.org>
PR libfortran/52434
PR libfortran/48878
PR libfortran/38199
* gfortran.dg/edit_real_1.f90: Don't assume roundTiesToAway.
* gfortran.dg/round_1.f03: Likewise.
From-SVN: r185433
This commit is contained in:
parent
ff63ac4d66
commit
37b659dd29
|
|
@ -1,3 +1,11 @@
|
||||||
|
2012-03-15 Janne Blomqvist <jb@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR libfortran/52434
|
||||||
|
PR libfortran/48878
|
||||||
|
PR libfortran/38199
|
||||||
|
* gfortran.dg/edit_real_1.f90: Don't assume roundTiesToAway.
|
||||||
|
* gfortran.dg/round_1.f03: Likewise.
|
||||||
|
|
||||||
2012-03-15 Jakub Jelinek <jakub@redhat.com>
|
2012-03-15 Jakub Jelinek <jakub@redhat.com>
|
||||||
Andrew Pinski <apinski@cavium.com>
|
Andrew Pinski <apinski@cavium.com>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ program edit_real_1
|
||||||
if (s .ne. '12.345E-01z') call abort
|
if (s .ne. '12.345E-01z') call abort
|
||||||
! E format, negative scale factor
|
! E format, negative scale factor
|
||||||
s = x
|
s = x
|
||||||
write (s, '(-2PE10.4,A)') 1.25, "z"
|
write (s, '(-2PE10.4,A)') 1.250001, "z"
|
||||||
if (s .ne. '0.0013E+03z') call abort
|
if (s .ne. '0.0013E+03z') call abort
|
||||||
! E format, single digit precision
|
! E format, single digit precision
|
||||||
s = x
|
s = x
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ write(line, fmt(4)) 1.20, 1.22, 1.25, 1.27, 1.30, 1.125
|
||||||
if (line.ne." 1.20 1.22 1.25 1.27 1.30 1.12") call abort
|
if (line.ne." 1.20 1.22 1.25 1.27 1.30 1.12") call abort
|
||||||
write(line, fmt(5)) 1.20, 1.22, 1.25, 1.27, 1.30, 1.125
|
write(line, fmt(5)) 1.20, 1.22, 1.25, 1.27, 1.30, 1.125
|
||||||
if (line.ne." 1.20 1.22 1.25 1.27 1.30 1.13") call abort
|
if (line.ne." 1.20 1.22 1.25 1.27 1.30 1.13") call abort
|
||||||
write(line, fmt(6)) 1.20, 1.22, 1.25, 1.27, 1.30, 1.125
|
write(line, fmt(6)) 1.20, 1.22, 1.250001, 1.27, 1.30, 1.125
|
||||||
if (line.ne." 1.2 1.2 1.3 1.3 1.3 1.1") call abort
|
if (line.ne." 1.2 1.2 1.3 1.3 1.3 1.1") call abort
|
||||||
write(line, fmt(7)) 1.20, 1.22, 1.25, 1.27, 1.30, 1.125
|
write(line, fmt(7)) 1.20, 1.22, 1.250001, 1.27, 1.30, 1.125
|
||||||
if (line.ne." +1.2 +1.2 +1.3 +1.3 +1.3 +1.1") call abort
|
if (line.ne." +1.2 +1.2 +1.3 +1.3 +1.3 +1.1") call abort
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,24 @@
|
||||||
|
2012-03-15 Janne Blomqvist <jb@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR libfortran/52434
|
||||||
|
PR libfortran/48878
|
||||||
|
PR libfortran/38199
|
||||||
|
* io/unit.c (get_internal_unit): Default to ROUND_UNSPECIFIED.
|
||||||
|
(init_units): Likewise.
|
||||||
|
* io/write_float.def (determine_precision): New function.
|
||||||
|
(output_float): Take into account buffer with %f format, no need
|
||||||
|
for our own rounding if unspecified or processor specified
|
||||||
|
rounding.
|
||||||
|
(DTOA): Simplify format string, add parameters.
|
||||||
|
(FDTOA): New macros similar to DTOA, but using %f format.
|
||||||
|
(OUTPUT_FLOAT_FMT_G): Stack allocate newf, determine correct
|
||||||
|
precision and fill buffer.
|
||||||
|
(EN_PREC): New macro.
|
||||||
|
(determine_en_precision): New function.
|
||||||
|
(WRITE_FLOAT): For G format, move buffer filling into
|
||||||
|
output_float_FMT_G, use FDTOA for F format.
|
||||||
|
(write_float): Increase buffer due to F format.
|
||||||
|
|
||||||
2012-03-14 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
|
2012-03-14 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
|
||||||
|
|
||||||
* intrinsics/c99_functions.c [__sgi__ && !HAVE_COMPLEX_H]: Remove.
|
* intrinsics/c99_functions.c [__sgi__ && !HAVE_COMPLEX_H]: Remove.
|
||||||
|
|
|
||||||
|
|
@ -453,7 +453,7 @@ get_internal_unit (st_parameter_dt *dtp)
|
||||||
iunit->flags.decimal = DECIMAL_POINT;
|
iunit->flags.decimal = DECIMAL_POINT;
|
||||||
iunit->flags.encoding = ENCODING_DEFAULT;
|
iunit->flags.encoding = ENCODING_DEFAULT;
|
||||||
iunit->flags.async = ASYNC_NO;
|
iunit->flags.async = ASYNC_NO;
|
||||||
iunit->flags.round = ROUND_COMPATIBLE;
|
iunit->flags.round = ROUND_UNSPECIFIED;
|
||||||
|
|
||||||
/* Initialize the data transfer parameters. */
|
/* Initialize the data transfer parameters. */
|
||||||
|
|
||||||
|
|
@ -543,7 +543,7 @@ init_units (void)
|
||||||
u->flags.decimal = DECIMAL_POINT;
|
u->flags.decimal = DECIMAL_POINT;
|
||||||
u->flags.encoding = ENCODING_DEFAULT;
|
u->flags.encoding = ENCODING_DEFAULT;
|
||||||
u->flags.async = ASYNC_NO;
|
u->flags.async = ASYNC_NO;
|
||||||
u->flags.round = ROUND_COMPATIBLE;
|
u->flags.round = ROUND_UNSPECIFIED;
|
||||||
|
|
||||||
u->recl = options.default_recl;
|
u->recl = options.default_recl;
|
||||||
u->endfile = NO_ENDFILE;
|
u->endfile = NO_ENDFILE;
|
||||||
|
|
@ -573,7 +573,7 @@ init_units (void)
|
||||||
u->flags.decimal = DECIMAL_POINT;
|
u->flags.decimal = DECIMAL_POINT;
|
||||||
u->flags.encoding = ENCODING_DEFAULT;
|
u->flags.encoding = ENCODING_DEFAULT;
|
||||||
u->flags.async = ASYNC_NO;
|
u->flags.async = ASYNC_NO;
|
||||||
u->flags.round = ROUND_COMPATIBLE;
|
u->flags.round = ROUND_UNSPECIFIED;
|
||||||
|
|
||||||
u->recl = options.default_recl;
|
u->recl = options.default_recl;
|
||||||
u->endfile = AT_ENDFILE;
|
u->endfile = AT_ENDFILE;
|
||||||
|
|
@ -603,7 +603,7 @@ init_units (void)
|
||||||
u->flags.decimal = DECIMAL_POINT;
|
u->flags.decimal = DECIMAL_POINT;
|
||||||
u->flags.encoding = ENCODING_DEFAULT;
|
u->flags.encoding = ENCODING_DEFAULT;
|
||||||
u->flags.async = ASYNC_NO;
|
u->flags.async = ASYNC_NO;
|
||||||
u->flags.round = ROUND_COMPATIBLE;
|
u->flags.round = ROUND_UNSPECIFIED;
|
||||||
|
|
||||||
u->recl = options.default_recl;
|
u->recl = options.default_recl;
|
||||||
u->endfile = AT_ENDFILE;
|
u->endfile = AT_ENDFILE;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
/* Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
|
/* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
|
||||||
|
Free Software Foundation, Inc.
|
||||||
Contributed by Andy Vaught
|
Contributed by Andy Vaught
|
||||||
Write float code factoring to this file by Jerry DeLisle
|
Write float code factoring to this file by Jerry DeLisle
|
||||||
F2003 I/O support contributed by Jerry DeLisle
|
F2003 I/O support contributed by Jerry DeLisle
|
||||||
|
|
@ -59,11 +60,60 @@ calculate_sign (st_parameter_dt *dtp, int negative_flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Determine the precision except for EN format. For G format,
|
||||||
|
determines an upper bound to be used for sizing the buffer. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
determine_precision (st_parameter_dt * dtp, const fnode * f, int len)
|
||||||
|
{
|
||||||
|
int precision = f->u.real.d;
|
||||||
|
|
||||||
|
switch (f->format)
|
||||||
|
{
|
||||||
|
case FMT_F:
|
||||||
|
case FMT_G:
|
||||||
|
precision += dtp->u.p.scale_factor;
|
||||||
|
break;
|
||||||
|
case FMT_ES:
|
||||||
|
/* Scale factor has no effect on output. */
|
||||||
|
break;
|
||||||
|
case FMT_E:
|
||||||
|
case FMT_D:
|
||||||
|
/* See F2008 10.7.2.3.3.6 */
|
||||||
|
if (dtp->u.p.scale_factor <= 0)
|
||||||
|
precision += dtp->u.p.scale_factor - 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the scale factor has a large negative value, we must do our
|
||||||
|
own rounding? Use ROUND='NEAREST', which should be what snprintf
|
||||||
|
is using as well. */
|
||||||
|
if (precision < 0 &&
|
||||||
|
(dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
|
||||||
|
|| dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
|
||||||
|
dtp->u.p.current_unit->round_status = ROUND_NEAREST;
|
||||||
|
|
||||||
|
/* Add extra guard digits up to at least full precision when we do
|
||||||
|
our own rounding. */
|
||||||
|
if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
|
||||||
|
&& dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
|
||||||
|
{
|
||||||
|
precision += 2 * len + 4;
|
||||||
|
if (precision < 0)
|
||||||
|
precision = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return precision;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Output a real number according to its format which is FMT_G free. */
|
/* Output a real number according to its format which is FMT_G free. */
|
||||||
|
|
||||||
static try
|
static try
|
||||||
output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
int sign_bit, bool zero_flag, int ndigits, int edigits)
|
int nprinted, int precision, int sign_bit, bool zero_flag)
|
||||||
{
|
{
|
||||||
char *out;
|
char *out;
|
||||||
char *digits;
|
char *digits;
|
||||||
|
|
@ -80,6 +130,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
int nzero_real;
|
int nzero_real;
|
||||||
int leadzero;
|
int leadzero;
|
||||||
int nblanks;
|
int nblanks;
|
||||||
|
int ndigits, edigits;
|
||||||
sign_t sign;
|
sign_t sign;
|
||||||
|
|
||||||
ft = f->format;
|
ft = f->format;
|
||||||
|
|
@ -96,50 +147,97 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
|
|
||||||
sign = calculate_sign (dtp, sign_bit);
|
sign = calculate_sign (dtp, sign_bit);
|
||||||
|
|
||||||
/* The following code checks the given string has punctuation in the correct
|
/* Calculate total number of digits. */
|
||||||
places. Uncomment if needed for debugging.
|
if (ft == FMT_F)
|
||||||
if (d != 0 && ((buffer[2] != '.' && buffer[2] != ',')
|
ndigits = nprinted - 2;
|
||||||
|| buffer[ndigits + 2] != 'e'))
|
else
|
||||||
internal_error (&dtp->common, "printf is broken"); */
|
ndigits = precision + 1;
|
||||||
|
|
||||||
/* Read the exponent back in. */
|
/* Read the exponent back in. */
|
||||||
e = atoi (&buffer[ndigits + 3]) + 1;
|
if (ft != FMT_F)
|
||||||
|
e = atoi (&buffer[ndigits + 3]) + 1;
|
||||||
|
else
|
||||||
|
e = 0;
|
||||||
|
|
||||||
/* Make sure zero comes out as 0.0e0. */
|
/* Make sure zero comes out as 0.0e0. */
|
||||||
if (zero_flag)
|
if (zero_flag)
|
||||||
e = 0;
|
e = 0;
|
||||||
|
|
||||||
/* Normalize the fractional component. */
|
/* Normalize the fractional component. */
|
||||||
buffer[2] = buffer[1];
|
if (ft != FMT_F)
|
||||||
digits = &buffer[2];
|
{
|
||||||
|
buffer[2] = buffer[1];
|
||||||
|
digits = &buffer[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
digits = &buffer[1];
|
||||||
|
|
||||||
/* Figure out where to place the decimal point. */
|
/* Figure out where to place the decimal point. */
|
||||||
switch (ft)
|
switch (ft)
|
||||||
{
|
{
|
||||||
case FMT_F:
|
case FMT_F:
|
||||||
if (d == 0 && e <= 0 && p == 0)
|
nbefore = ndigits - precision;
|
||||||
|
/* Make sure the decimal point is a '.'; depending on the
|
||||||
|
locale, this might not be the case otherwise. */
|
||||||
|
digits[nbefore] = '.';
|
||||||
|
if (digits[0] == '0' && nbefore == 1)
|
||||||
{
|
{
|
||||||
memmove (digits + 1, digits, ndigits - 1);
|
digits++;
|
||||||
digits[0] = '0';
|
nbefore--;
|
||||||
e++;
|
ndigits--;
|
||||||
}
|
}
|
||||||
|
//printf("nbefore: %d, digits: %s\n", nbefore, digits);
|
||||||
nbefore = e + p;
|
if (p != 0)
|
||||||
if (nbefore < 0)
|
|
||||||
{
|
{
|
||||||
nzero = -nbefore;
|
if (p > 0)
|
||||||
nzero_real = nzero;
|
{
|
||||||
if (nzero > d)
|
|
||||||
nzero = d;
|
memmove (digits + nbefore, digits + nbefore + 1, p);
|
||||||
nafter = d - nzero;
|
digits[nbefore + p] = '.';
|
||||||
nbefore = 0;
|
nbefore += p;
|
||||||
|
nafter = d - p;
|
||||||
|
if (nafter < 0)
|
||||||
|
nafter = 0;
|
||||||
|
nafter = d;
|
||||||
|
nzero = nzero_real = 0;
|
||||||
|
//printf("digits: %s\n", digits);
|
||||||
|
}
|
||||||
|
else /* p < 0 */
|
||||||
|
{
|
||||||
|
if (nbefore + p >= 0)
|
||||||
|
{
|
||||||
|
nzero = 0;
|
||||||
|
memmove (digits + nbefore + p + 1, digits + nbefore + p, -p);
|
||||||
|
nbefore += p;
|
||||||
|
digits[nbefore] = '.';
|
||||||
|
nafter = d;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nzero = -(nbefore + p);
|
||||||
|
memmove (digits + 1, digits, nbefore);
|
||||||
|
digits++;
|
||||||
|
nafter = d + nbefore;
|
||||||
|
nbefore = 0;
|
||||||
|
}
|
||||||
|
nzero_real = nzero;
|
||||||
|
if (nzero > d)
|
||||||
|
nzero = d;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nzero = 0;
|
nzero = nzero_real = 0;
|
||||||
nafter = d;
|
nafter = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
expchar = 0;
|
expchar = 0;
|
||||||
|
/* If we need to do rounding ourselves, get rid of the dot by
|
||||||
|
moving the fractional part. */
|
||||||
|
if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
|
||||||
|
&& dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
|
||||||
|
memmove (digits + nbefore, digits + nbefore + 1, ndigits - nbefore);
|
||||||
|
//printf("nbefore after p handling: %d, digits: %s\n", nbefore, digits);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FMT_E:
|
case FMT_E:
|
||||||
|
|
@ -222,10 +320,16 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
if (zero_flag)
|
if (zero_flag)
|
||||||
goto skip;
|
goto skip;
|
||||||
|
|
||||||
/* Round the value. The value being rounded is an unsigned magnitude.
|
/* Round the value. The value being rounded is an unsigned magnitude. */
|
||||||
The ROUND_COMPATIBLE is rounding away from zero when there is a tie. */
|
|
||||||
switch (dtp->u.p.current_unit->round_status)
|
switch (dtp->u.p.current_unit->round_status)
|
||||||
{
|
{
|
||||||
|
/* For processor defined and unspecified rounding we use
|
||||||
|
snprintf to print the exact number of digits needed, and thus
|
||||||
|
let snprintf handle the rounding. On system claiming support
|
||||||
|
for IEEE 754, this ought to be round to nearest, ties to
|
||||||
|
even, corresponding to the Fortran ROUND='NEAREST'. */
|
||||||
|
case ROUND_PROCDEFINED:
|
||||||
|
case ROUND_UNSPECIFIED:
|
||||||
case ROUND_ZERO: /* Do nothing and truncation occurs. */
|
case ROUND_ZERO: /* Do nothing and truncation occurs. */
|
||||||
goto skip;
|
goto skip;
|
||||||
case ROUND_UP:
|
case ROUND_UP:
|
||||||
|
|
@ -240,6 +344,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
/* Round compatible unless there is a tie. A tie is a 5 with
|
/* Round compatible unless there is a tie. A tie is a 5 with
|
||||||
all trailing zero's. */
|
all trailing zero's. */
|
||||||
i = nafter + nbefore;
|
i = nafter + nbefore;
|
||||||
|
//printf("I = %d, digits = %s, nbefore = %d\n", i, digits, nbefore);
|
||||||
if (digits[i] == '5')
|
if (digits[i] == '5')
|
||||||
{
|
{
|
||||||
for(i++ ; i < ndigits; i++)
|
for(i++ ; i < ndigits; i++)
|
||||||
|
|
@ -262,9 +367,8 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Fall through. */
|
/* Fall through. */
|
||||||
case ROUND_PROCDEFINED:
|
/* The ROUND_COMPATIBLE is rounding away from zero when there is a tie. */
|
||||||
case ROUND_UNSPECIFIED:
|
|
||||||
case ROUND_COMPATIBLE:
|
case ROUND_COMPATIBLE:
|
||||||
rchar = '5';
|
rchar = '5';
|
||||||
goto do_rnd;
|
goto do_rnd;
|
||||||
|
|
@ -300,6 +404,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
else if (nbefore + nafter < ndigits)
|
else if (nbefore + nafter < ndigits)
|
||||||
{
|
{
|
||||||
i = ndigits = nbefore + nafter;
|
i = ndigits = nbefore + nafter;
|
||||||
|
//printf("i: %d, digits: %s, nbefore: %d, nafter: %d\n", i, digits, nbefore, nafter);
|
||||||
if (digits[i] >= rchar)
|
if (digits[i] >= rchar)
|
||||||
{
|
{
|
||||||
/* Propagate the carry. */
|
/* Propagate the carry. */
|
||||||
|
|
@ -384,7 +489,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
rounding completed above. */
|
rounding completed above. */
|
||||||
for (i = 0; i < ndigits; i++)
|
for (i = 0; i < ndigits; i++)
|
||||||
{
|
{
|
||||||
if (digits[i] != '0')
|
if (digits[i] != '0' && digits[i] != '.')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -502,6 +607,10 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
/* Output the decimal point. */
|
/* Output the decimal point. */
|
||||||
*(out4++) = dtp->u.p.current_unit->decimal_status
|
*(out4++) = dtp->u.p.current_unit->decimal_status
|
||||||
== DECIMAL_POINT ? '.' : ',';
|
== DECIMAL_POINT ? '.' : ',';
|
||||||
|
if (ft == FMT_F
|
||||||
|
&& (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
|
||||||
|
|| dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
|
||||||
|
digits++;
|
||||||
|
|
||||||
/* Output leading zeros after the decimal point. */
|
/* Output leading zeros after the decimal point. */
|
||||||
if (nzero > 0)
|
if (nzero > 0)
|
||||||
|
|
@ -590,6 +699,10 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
|
|
||||||
/* Output the decimal point. */
|
/* Output the decimal point. */
|
||||||
*(out++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
|
*(out++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
|
||||||
|
if (ft == FMT_F
|
||||||
|
&& (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
|
||||||
|
|| dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
|
||||||
|
digits++;
|
||||||
|
|
||||||
/* Output leading zeros after the decimal point. */
|
/* Output leading zeros after the decimal point. */
|
||||||
if (nzero > 0)
|
if (nzero > 0)
|
||||||
|
|
@ -634,9 +747,6 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
dtp->u.p.no_leading_blank = 0;
|
dtp->u.p.no_leading_blank = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef STR
|
|
||||||
#undef STR1
|
|
||||||
#undef MIN_FIELD_WIDTH
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -798,6 +908,61 @@ CALCULATE_EXP(16)
|
||||||
#endif
|
#endif
|
||||||
#undef CALCULATE_EXP
|
#undef CALCULATE_EXP
|
||||||
|
|
||||||
|
|
||||||
|
/* Define a macro to build code for write_float. */
|
||||||
|
|
||||||
|
/* Note: Before output_float is called, snprintf is used to print to buffer the
|
||||||
|
number in the format +D.DDDDe+ddd.
|
||||||
|
|
||||||
|
# The result will always contain a decimal point, even if no
|
||||||
|
digits follow it
|
||||||
|
|
||||||
|
- The converted value is to be left adjusted on the field boundary
|
||||||
|
|
||||||
|
+ A sign (+ or -) always be placed before a number
|
||||||
|
|
||||||
|
* prec is used as the precision
|
||||||
|
|
||||||
|
e format: [-]d.ddde±dd where there is one digit before the
|
||||||
|
decimal-point character and the number of digits after it is
|
||||||
|
equal to the precision. The exponent always contains at least two
|
||||||
|
digits; if the value is zero, the exponent is 00. */
|
||||||
|
|
||||||
|
|
||||||
|
#define TOKENPASTE(x, y) TOKENPASTE2(x, y)
|
||||||
|
#define TOKENPASTE2(x, y) x ## y
|
||||||
|
|
||||||
|
#define DTOA(suff,prec,val) TOKENPASTE(DTOA2,suff)(prec,val)
|
||||||
|
|
||||||
|
#define DTOA2(prec,val) \
|
||||||
|
snprintf (buffer, size, "%+-#.*e", (prec), (val))
|
||||||
|
|
||||||
|
#define DTOA2L(prec,val) \
|
||||||
|
snprintf (buffer, size, "%+-#.*Le", (prec), (val))
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(GFC_REAL_16_IS_FLOAT128)
|
||||||
|
#define DTOA2Q(prec,val) \
|
||||||
|
__qmath_(quadmath_snprintf) (buffer, size, "%+-#.*Qe", (prec), (val))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FDTOA(suff,prec,val) TOKENPASTE(FDTOA2,suff)(prec,val)
|
||||||
|
|
||||||
|
/* For F format, we print to the buffer with f format. */
|
||||||
|
#define FDTOA2(prec,val) \
|
||||||
|
snprintf (buffer, size, "%+-#.*f", (prec), (val))
|
||||||
|
|
||||||
|
#define FDTOA2L(prec,val) \
|
||||||
|
snprintf (buffer, size, "%+-#.*Lf", (prec), (val))
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(GFC_REAL_16_IS_FLOAT128)
|
||||||
|
#define FDTOA2Q(prec,val) \
|
||||||
|
__qmath_(quadmath_snprintf) (buffer, size, "%+-#.*Qf", \
|
||||||
|
(prec), (val))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Generate corresponding I/O format for FMT_G and output.
|
/* Generate corresponding I/O format for FMT_G and output.
|
||||||
The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
|
The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
|
||||||
LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
|
LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
|
||||||
|
|
@ -817,26 +982,25 @@ CALCULATE_EXP(16)
|
||||||
for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
|
for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
|
||||||
the asm volatile is required for 32-bit x86 platforms. */
|
the asm volatile is required for 32-bit x86 platforms. */
|
||||||
|
|
||||||
#define OUTPUT_FLOAT_FMT_G(x) \
|
#define OUTPUT_FLOAT_FMT_G(x,y) \
|
||||||
static void \
|
static void \
|
||||||
output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
|
output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
|
||||||
GFC_REAL_ ## x m, char *buffer, size_t size, \
|
GFC_REAL_ ## x m, char *buffer, size_t size, \
|
||||||
int sign_bit, bool zero_flag, int ndigits, \
|
int sign_bit, bool zero_flag, int comp_d) \
|
||||||
int edigits, int comp_d) \
|
|
||||||
{ \
|
{ \
|
||||||
int e = f->u.real.e;\
|
int e = f->u.real.e;\
|
||||||
int d = f->u.real.d;\
|
int d = f->u.real.d;\
|
||||||
int w = f->u.real.w;\
|
int w = f->u.real.w;\
|
||||||
fnode *newf;\
|
fnode newf;\
|
||||||
GFC_REAL_ ## x rexp_d, r = 0.5;\
|
GFC_REAL_ ## x rexp_d, r = 0.5;\
|
||||||
int low, high, mid;\
|
int low, high, mid;\
|
||||||
int ubound, lbound;\
|
int ubound, lbound;\
|
||||||
char *p, pad = ' ';\
|
char *p, pad = ' ';\
|
||||||
int save_scale_factor, nb = 0;\
|
int save_scale_factor, nb = 0;\
|
||||||
try result;\
|
try result;\
|
||||||
|
int nprinted, precision;\
|
||||||
\
|
\
|
||||||
save_scale_factor = dtp->u.p.scale_factor;\
|
save_scale_factor = dtp->u.p.scale_factor;\
|
||||||
newf = (fnode *) get_mem (sizeof (fnode));\
|
|
||||||
\
|
\
|
||||||
switch (dtp->u.p.current_unit->round_status)\
|
switch (dtp->u.p.current_unit->round_status)\
|
||||||
{\
|
{\
|
||||||
|
|
@ -858,11 +1022,13 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
|
||||||
|| ((m == 0.0) && !(compile_options.allow_std\
|
|| ((m == 0.0) && !(compile_options.allow_std\
|
||||||
& (GFC_STD_F2003 | GFC_STD_F2008))))\
|
& (GFC_STD_F2003 | GFC_STD_F2008))))\
|
||||||
{ \
|
{ \
|
||||||
newf->format = FMT_E;\
|
newf.format = FMT_E;\
|
||||||
newf->u.real.w = w;\
|
newf.u.real.w = w;\
|
||||||
newf->u.real.d = d - comp_d;\
|
newf.u.real.d = d - comp_d;\
|
||||||
newf->u.real.e = e;\
|
newf.u.real.e = e;\
|
||||||
nb = 0;\
|
nb = 0;\
|
||||||
|
precision = determine_precision (dtp, &newf, x);\
|
||||||
|
nprinted = DTOA(y,precision,m); \
|
||||||
goto finish;\
|
goto finish;\
|
||||||
}\
|
}\
|
||||||
\
|
\
|
||||||
|
|
@ -905,17 +1071,18 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
|
||||||
\
|
\
|
||||||
nb = e <= 0 ? 4 : e + 2;\
|
nb = e <= 0 ? 4 : e + 2;\
|
||||||
nb = nb >= w ? w - 1 : nb;\
|
nb = nb >= w ? w - 1 : nb;\
|
||||||
newf->format = FMT_F;\
|
newf.format = FMT_F;\
|
||||||
newf->u.real.w = w - nb;\
|
newf.u.real.w = w - nb;\
|
||||||
newf->u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
|
newf.u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
|
||||||
dtp->u.p.scale_factor = 0;\
|
dtp->u.p.scale_factor = 0;\
|
||||||
|
precision = determine_precision (dtp, &newf, x); \
|
||||||
|
nprinted = FDTOA(y,precision,m); \
|
||||||
\
|
\
|
||||||
finish:\
|
finish:\
|
||||||
result = output_float (dtp, newf, buffer, size, sign_bit, zero_flag, \
|
result = output_float (dtp, &newf, buffer, size, nprinted, precision,\
|
||||||
ndigits, edigits);\
|
sign_bit, zero_flag);\
|
||||||
dtp->u.p.scale_factor = save_scale_factor;\
|
dtp->u.p.scale_factor = save_scale_factor;\
|
||||||
\
|
\
|
||||||
free (newf);\
|
|
||||||
\
|
\
|
||||||
if (nb > 0 && !dtp->u.p.g0_no_blanks)\
|
if (nb > 0 && !dtp->u.p.g0_no_blanks)\
|
||||||
{\
|
{\
|
||||||
|
|
@ -934,59 +1101,96 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
|
||||||
}\
|
}\
|
||||||
}\
|
}\
|
||||||
|
|
||||||
OUTPUT_FLOAT_FMT_G(4)
|
OUTPUT_FLOAT_FMT_G(4,)
|
||||||
|
|
||||||
OUTPUT_FLOAT_FMT_G(8)
|
OUTPUT_FLOAT_FMT_G(8,)
|
||||||
|
|
||||||
#ifdef HAVE_GFC_REAL_10
|
#ifdef HAVE_GFC_REAL_10
|
||||||
OUTPUT_FLOAT_FMT_G(10)
|
OUTPUT_FLOAT_FMT_G(10,L)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_GFC_REAL_16
|
#ifdef HAVE_GFC_REAL_16
|
||||||
OUTPUT_FLOAT_FMT_G(16)
|
# ifdef GFC_REAL_16_IS_FLOAT128
|
||||||
|
OUTPUT_FLOAT_FMT_G(16,Q)
|
||||||
|
#else
|
||||||
|
OUTPUT_FLOAT_FMT_G(16,L)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef OUTPUT_FLOAT_FMT_G
|
#undef OUTPUT_FLOAT_FMT_G
|
||||||
|
|
||||||
|
|
||||||
/* Define a macro to build code for write_float. */
|
/* EN format is tricky since the number of significant digits depends
|
||||||
|
on the magnitude. Solve it by first printing a temporary value and
|
||||||
|
figure out the number of significant digits from the printed
|
||||||
|
exponent. */
|
||||||
|
|
||||||
/* Note: Before output_float is called, snprintf is used to print to buffer the
|
#define EN_PREC(x,y)\
|
||||||
number in the format +D.DDDDe+ddd. For an N digit exponent, this gives us
|
{\
|
||||||
(MIN_FIELD_WIDTH-5)-N digits after the decimal point, plus another one
|
GFC_REAL_ ## x tmp; \
|
||||||
before the decimal point.
|
tmp = * (GFC_REAL_ ## x *)source; \
|
||||||
|
if (isfinite (tmp)) \
|
||||||
|
nprinted = DTOA(y,0,tmp); \
|
||||||
|
else\
|
||||||
|
nprinted = -1;\
|
||||||
|
}\
|
||||||
|
|
||||||
# The result will always contain a decimal point, even if no
|
static int
|
||||||
digits follow it
|
determine_en_precision (st_parameter_dt *dtp, const fnode *f,
|
||||||
|
const char *source, int len)
|
||||||
|
{
|
||||||
|
int nprinted;
|
||||||
|
char buffer[10];
|
||||||
|
const size_t size = 10;
|
||||||
|
|
||||||
- The converted value is to be left adjusted on the field boundary
|
switch (len)
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
EN_PREC(4,)
|
||||||
|
break;
|
||||||
|
|
||||||
+ A sign (+ or -) always be placed before a number
|
case 8:
|
||||||
|
EN_PREC(8,)
|
||||||
|
break;
|
||||||
|
|
||||||
MIN_FIELD_WIDTH minimum field width
|
#ifdef HAVE_GFC_REAL_10
|
||||||
|
case 10:
|
||||||
* (ndigits-1) is used as the precision
|
EN_PREC(10,L)
|
||||||
|
break;
|
||||||
e format: [-]d.ddde±dd where there is one digit before the
|
|
||||||
decimal-point character and the number of digits after it is
|
|
||||||
equal to the precision. The exponent always contains at least two
|
|
||||||
digits; if the value is zero, the exponent is 00. */
|
|
||||||
|
|
||||||
#define DTOA \
|
|
||||||
snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
|
|
||||||
"e", ndigits - 1, tmp);
|
|
||||||
|
|
||||||
#define DTOAL \
|
|
||||||
snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
|
|
||||||
"Le", ndigits - 1, tmp);
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(GFC_REAL_16_IS_FLOAT128)
|
|
||||||
#define DTOAQ \
|
|
||||||
__qmath_(quadmath_snprintf) (buffer, sizeof buffer, \
|
|
||||||
"%+-#" STR(MIN_FIELD_WIDTH) ".*" \
|
|
||||||
"Qe", ndigits - 1, tmp);
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_GFC_REAL_16
|
||||||
|
case 16:
|
||||||
|
# ifdef GFC_REAL_16_IS_FLOAT128
|
||||||
|
EN_PREC(16,Q)
|
||||||
|
# else
|
||||||
|
EN_PREC(16,L)
|
||||||
|
# endif
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
internal_error (NULL, "bad real kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nprinted == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int e = atoi (&buffer[5]);
|
||||||
|
int nbefore; /* digits before decimal point - 1. */
|
||||||
|
if (e >= 0)
|
||||||
|
nbefore = e % 3;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nbefore = (-e) % 3;
|
||||||
|
if (nbefore != 0)
|
||||||
|
nbefore = 3 - nbefore;
|
||||||
|
}
|
||||||
|
int prec = f->u.real.d + nbefore;
|
||||||
|
if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
|
||||||
|
&& dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
|
||||||
|
prec += 2 * len + 4;
|
||||||
|
return prec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define WRITE_FLOAT(x,y)\
|
#define WRITE_FLOAT(x,y)\
|
||||||
{\
|
{\
|
||||||
|
|
@ -1000,15 +1204,18 @@ __qmath_(quadmath_snprintf) (buffer, sizeof buffer, \
|
||||||
}\
|
}\
|
||||||
tmp = sign_bit ? -tmp : tmp;\
|
tmp = sign_bit ? -tmp : tmp;\
|
||||||
zero_flag = (tmp == 0.0);\
|
zero_flag = (tmp == 0.0);\
|
||||||
\
|
if (f->format == FMT_G)\
|
||||||
DTOA ## y\
|
|
||||||
\
|
|
||||||
if (f->format != FMT_G)\
|
|
||||||
output_float (dtp, f, buffer, size, sign_bit, zero_flag, ndigits, \
|
|
||||||
edigits);\
|
|
||||||
else \
|
|
||||||
output_float_FMT_G_ ## x (dtp, f, tmp, buffer, size, sign_bit, \
|
output_float_FMT_G_ ## x (dtp, f, tmp, buffer, size, sign_bit, \
|
||||||
zero_flag, ndigits, edigits, comp_d);\
|
zero_flag, comp_d);\
|
||||||
|
else\
|
||||||
|
{\
|
||||||
|
if (f->format == FMT_F)\
|
||||||
|
nprinted = FDTOA(y,precision,tmp); \
|
||||||
|
else\
|
||||||
|
nprinted = DTOA(y,precision,tmp); \
|
||||||
|
output_float (dtp, f, buffer, size, nprinted, precision,\
|
||||||
|
sign_bit, zero_flag);\
|
||||||
|
}\
|
||||||
}\
|
}\
|
||||||
|
|
||||||
/* Output a real number according to its format. */
|
/* Output a real number according to its format. */
|
||||||
|
|
@ -1017,29 +1224,21 @@ static void
|
||||||
write_float (st_parameter_dt *dtp, const fnode *f, const char *source, \
|
write_float (st_parameter_dt *dtp, const fnode *f, const char *source, \
|
||||||
int len, int comp_d)
|
int len, int comp_d)
|
||||||
{
|
{
|
||||||
|
int sign_bit, nprinted;
|
||||||
#if defined(HAVE_GFC_REAL_16) || __LDBL_DIG__ > 18
|
int precision; /* Precision for snprintf call. */
|
||||||
# define MIN_FIELD_WIDTH 49
|
|
||||||
#else
|
|
||||||
# define MIN_FIELD_WIDTH 32
|
|
||||||
#endif
|
|
||||||
#define STR(x) STR1(x)
|
|
||||||
#define STR1(x) #x
|
|
||||||
|
|
||||||
/* This must be large enough to accurately hold any value. */
|
|
||||||
char buffer[MIN_FIELD_WIDTH+1];
|
|
||||||
int sign_bit, ndigits, edigits;
|
|
||||||
bool zero_flag;
|
bool zero_flag;
|
||||||
size_t size;
|
|
||||||
|
|
||||||
size = MIN_FIELD_WIDTH+1;
|
if (f->format != FMT_EN)
|
||||||
|
precision = determine_precision (dtp, f, len);
|
||||||
|
else
|
||||||
|
precision = determine_en_precision (dtp, f, source, len);
|
||||||
|
|
||||||
/* printf pads blanks for us on the exponent so we just need it big enough
|
/* 4932 is the maximum exponent of long double and quad precision, 3
|
||||||
to handle the largest number of exponent digits expected. */
|
extra characters for the sign, the decimal point, and the
|
||||||
edigits=4;
|
trailing null, and finally some extra digits depending on the
|
||||||
|
requested precision. */
|
||||||
/* Always convert at full precision to avoid double rounding. */
|
const size_t size = 4932 + 3 + precision;
|
||||||
ndigits = MIN_FIELD_WIDTH - 4 - edigits;
|
char buffer[size];
|
||||||
|
|
||||||
switch (len)
|
switch (len)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue