mirror of git://gcc.gnu.org/git/gcc.git
re PR libfortran/48852 (Invalid spaces in list-directed output of complex constants)
2016-06-23 Jerry DeLisle <jvdelisle@gcc.gnu.org> PR libgfortran/48852 * io/write.c: Cleaned up whitespace. (write_d, write_e, write_f, write_es, write_en): Use new helper function write_float_0. (write_float_0): New helper function. (get_precision, select_buffer, select_string, write_float_string): New helper functions used in remaining float writing functions. Helper function write_float_string now contains code for writing to kind=4 character internal units. (write_real): Modified to establish working buffers at this level and to use new helper functions. (write_real_g0): Likewise modified. (write_complex): Likewise modified. Gets both float strings before output so that final lengths can be determined which allows right justifying the complex number with no intervening spaces. * io/write_float.def (build_float_string): Renamed from previosly output_float, modified to use buffers passed in from higher functions, builds a null terminated string of the floating point value. Character kind=4 code eliminated. (write_infnan): Likewise modified to use incoming buffers and eliminate kind=4 related code. (OUTPUT_FLOAT_FMT_G): Deleted, functionality moved into FORMAT_FLOAT. (FORMAT_FLOAT): Renamed macro from WRITE_FLOAT. Use build_float_string. (get_float_string): Renamed from write_float, uses FORMAT_FLOAT macro. Buffer allocation removed, now at higher level. PR libgfortran/48852 * gfortran.dg/char4_iunit_1.f03: Update test. * gfortran.dg/f2003_io_5.f03: Update test. * gfortran.dg/real_const_3.f90: Update test. From-SVN: r237735
This commit is contained in:
parent
cd64be5bca
commit
5b0e27a724
|
|
@ -1,3 +1,10 @@
|
||||||
|
2016-06-23 Jerry DeLisle <jvdelisle@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR libgfortran/48852
|
||||||
|
* gfortran.dg/char4_iunit_1.f03: Update test.
|
||||||
|
* gfortran.dg/f2003_io_5.f03: Update test.
|
||||||
|
* gfortran.dg/real_const_3.f90: Update test.
|
||||||
|
|
||||||
2016-06-23 Andi Kleen <ak@linux.intel.com>
|
2016-06-23 Andi Kleen <ak@linux.intel.com>
|
||||||
|
|
||||||
* g++.dg/bprob/bprob.exp: Support autofdo.
|
* g++.dg/bprob/bprob.exp: Support autofdo.
|
||||||
|
|
|
||||||
|
|
@ -30,5 +30,5 @@ program char4_iunit_1
|
||||||
write(string, '(10x,f3.1,3x,f9.1)') nan, inf
|
write(string, '(10x,f3.1,3x,f9.1)') nan, inf
|
||||||
if (string .ne. 4_" NaN Infinity ") call abort
|
if (string .ne. 4_" NaN Infinity ") call abort
|
||||||
write(string, *) (1.2, 3.4 )
|
write(string, *) (1.2, 3.4 )
|
||||||
if (string .ne. 4_" ( 1.20000005 , 3.40000010 ) ") call abort
|
if (string .ne. 4_" (1.20000005,3.40000010)") call abort
|
||||||
end program char4_iunit_1
|
end program char4_iunit_1
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ close(99, status="delete")
|
||||||
|
|
||||||
c = (3.123,4.456)
|
c = (3.123,4.456)
|
||||||
write(complex,*,decimal="comma") c
|
write(complex,*,decimal="comma") c
|
||||||
if (complex.ne." ( 3,12299991 ; 4,45599985 )") call abort
|
if (complex.ne." (3,12299991;4,45599985)") call abort
|
||||||
c = (0.0, 0.0)
|
c = (0.0, 0.0)
|
||||||
read(complex,*,decimal="comma") c
|
read(complex,*,decimal="comma") c
|
||||||
if (complex.ne." ( 3,12299991 ; 4,45599985 )") call abort
|
if (complex.ne." (3,12299991;4,45599985)") call abort
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -42,15 +42,14 @@ program main
|
||||||
if (trim(adjustl(str)) .ne. 'NaN') call abort
|
if (trim(adjustl(str)) .ne. 'NaN') call abort
|
||||||
|
|
||||||
write(str,*) z
|
write(str,*) z
|
||||||
if (trim(adjustl(str)) .ne. '( NaN, NaN)') call abort
|
if (trim(adjustl(str)) .ne. '(NaN,NaN)') call abort
|
||||||
|
|
||||||
write(str,*) z2
|
write(str,*) z2
|
||||||
if (trim(adjustl(str)) .ne. '( NaN, NaN)') call abort
|
if (trim(adjustl(str)) .ne. '(NaN,NaN)') call abort
|
||||||
|
|
||||||
write(str,*) z3
|
write(str,*) z3
|
||||||
if (trim(adjustl(str)) .ne. '( Infinity, -Infinity)') call abort
|
if (trim(adjustl(str)) .ne. '(Inf,-Inf)') call abort
|
||||||
|
|
||||||
write(str,*) z4
|
write(str,*) z4
|
||||||
if (trim(adjustl(str)) .ne. '( 0.00000000 , -0.00000000 )') call abort
|
if (trim(adjustl(str)) .ne. '(0.00000000,-0.00000000)') call abort
|
||||||
|
|
||||||
end program main
|
end program main
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,30 @@
|
||||||
|
2016-06-23 Jerry DeLisle <jvdelisle@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR libgfortran/48852
|
||||||
|
* io/write.c: Cleaned up whitespace.
|
||||||
|
(write_d, write_e, write_f, write_es, write_en): Use new helper function
|
||||||
|
write_float_0. (write_float_0): New helper function.
|
||||||
|
(get_precision, select_buffer, select_string, write_float_string): New
|
||||||
|
helper functions used in remaining float writing functions. Helper function
|
||||||
|
write_float_string now contains code for writing to kind=4 character
|
||||||
|
internal units.
|
||||||
|
(write_real): Modified to establish working buffers at this level and to
|
||||||
|
use new helper functions.
|
||||||
|
(write_real_g0): Likewise modified.
|
||||||
|
(write_complex): Likewise modified. Gets both float strings before
|
||||||
|
output so that final lengths can be determined which allows right
|
||||||
|
justifying the complex number with no intervening spaces.
|
||||||
|
* io/write_float.def (build_float_string): Renamed from previosly
|
||||||
|
output_float, modified to use buffers passed in from higher functions,
|
||||||
|
builds a null terminated string of the floating point value. Character
|
||||||
|
kind=4 code eliminated.
|
||||||
|
(write_infnan): Likewise modified to use incoming buffers and eliminate
|
||||||
|
kind=4 related code.
|
||||||
|
(OUTPUT_FLOAT_FMT_G): Deleted, functionality moved into FORMAT_FLOAT.
|
||||||
|
(FORMAT_FLOAT): Renamed macro from WRITE_FLOAT. Use build_float_string.
|
||||||
|
(get_float_string): Renamed from write_float, uses FORMAT_FLOAT macro.
|
||||||
|
Buffer allocation removed, now at higher level.
|
||||||
|
|
||||||
2016-05-23 Jerry DeLisle <jvdelisle@gcc.gnu.org>
|
2016-05-23 Jerry DeLisle <jvdelisle@gcc.gnu.org>
|
||||||
|
|
||||||
PR libgfortran/71123
|
PR libgfortran/71123
|
||||||
|
|
|
||||||
|
|
@ -1101,42 +1101,6 @@ 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, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
write_e (st_parameter_dt *dtp, const fnode *f, const char *p, int 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, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
write_en (st_parameter_dt *dtp, const fnode *f, const char *p, int 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, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Take care of the X/TR descriptor. */
|
/* Take care of the X/TR descriptor. */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1380,6 +1344,119 @@ write_character (st_parameter_dt *dtp, const char *source, int kind, int length,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Floating point helper functions. */
|
||||||
|
|
||||||
|
#define BUF_STACK_SZ 256
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_precision (st_parameter_dt *dtp, const fnode *f, const char *source, int kind)
|
||||||
|
{
|
||||||
|
if (f->format != FMT_EN)
|
||||||
|
return determine_precision (dtp, f, kind);
|
||||||
|
else
|
||||||
|
return determine_en_precision (dtp, f, source, kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
select_buffer (int precision, char *buf, size_t *size)
|
||||||
|
{
|
||||||
|
char *result;
|
||||||
|
*size = BUF_STACK_SZ / 2 + precision;
|
||||||
|
if (*size > BUF_STACK_SZ)
|
||||||
|
result = xmalloc (*size);
|
||||||
|
else
|
||||||
|
result = buf;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
select_string (const fnode *f, char *buf, size_t *size)
|
||||||
|
{
|
||||||
|
char *result;
|
||||||
|
*size = f->u.real.w + 1;
|
||||||
|
if (*size > BUF_STACK_SZ)
|
||||||
|
result = xmalloc (*size);
|
||||||
|
else
|
||||||
|
result = buf;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_float_string (st_parameter_dt *dtp, char *fstr, size_t len)
|
||||||
|
{
|
||||||
|
char *p = write_block (dtp, len);
|
||||||
|
if (p == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (unlikely (is_char4_unit (dtp)))
|
||||||
|
{
|
||||||
|
gfc_char4_t *p4 = (gfc_char4_t *) p;
|
||||||
|
memcpy4 (p4, fstr, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy (p, fstr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_float_0 (st_parameter_dt *dtp, const fnode *f, const char *source, int kind)
|
||||||
|
{
|
||||||
|
char buf_stack[BUF_STACK_SZ];
|
||||||
|
char str_buf[BUF_STACK_SZ];
|
||||||
|
char *buffer, *result;
|
||||||
|
size_t buf_size, res_len;
|
||||||
|
|
||||||
|
/* Precision for snprintf call. */
|
||||||
|
int precision = get_precision (dtp, f, source, kind);
|
||||||
|
|
||||||
|
/* String buffer to hold final result. */
|
||||||
|
result = select_string (f, str_buf, &res_len);
|
||||||
|
|
||||||
|
buffer = select_buffer (precision, buf_stack, &buf_size);
|
||||||
|
|
||||||
|
get_float_string (dtp, f, source , kind, 0, buffer,
|
||||||
|
precision, buf_size, result, &res_len);
|
||||||
|
write_float_string (dtp, result, res_len);
|
||||||
|
|
||||||
|
if (buf_size > BUF_STACK_SZ)
|
||||||
|
free (buffer);
|
||||||
|
if (res_len > BUF_STACK_SZ)
|
||||||
|
free (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
write_d (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
|
||||||
|
{
|
||||||
|
write_float_0 (dtp, f, p, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
write_e (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
|
||||||
|
{
|
||||||
|
write_float_0 (dtp, f, p, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
write_f (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
|
||||||
|
{
|
||||||
|
write_float_0 (dtp, f, p, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
write_en (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
|
||||||
|
{
|
||||||
|
write_float_0 (dtp, f, p, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
write_es (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
|
||||||
|
{
|
||||||
|
write_float_0 (dtp, f, p, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set an fnode to default format. */
|
/* Set an fnode to default format. */
|
||||||
|
|
||||||
|
|
@ -1422,12 +1499,12 @@ set_fnode_default (st_parameter_dt *dtp, fnode *f, int length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output a real number with default format. To guarantee that a
|
/* Output a real number with default format.
|
||||||
binary -> decimal -> binary roundtrip conversion recovers the
|
To guarantee that a binary -> decimal -> binary roundtrip conversion
|
||||||
original value, IEEE 754-2008 requires 9, 17, 21 and 36 significant
|
recovers the original value, IEEE 754-2008 requires 9, 17, 21 and 36
|
||||||
digits for REAL kinds 4, 8, 10, and 16, respectively. Thus, we use
|
significant digits for REAL kinds 4, 8, 10, and 16, respectively.
|
||||||
1PG16.9E2 for REAL(4), 1PG25.17E3 for REAL(8), 1PG30.21E4 for
|
Thus, we use 1PG16.9E2 for REAL(4), 1PG25.17E3 for REAL(8), 1PG30.21E4
|
||||||
REAL(10) and 1PG45.36E4 for REAL(16). The exception is that the
|
for REAL(10) and 1PG45.36E4 for REAL(16). The exception is that the
|
||||||
Fortran standard requires outputting an extra digit when the scale
|
Fortran standard requires outputting an extra digit when the scale
|
||||||
factor is 1 and when the magnitude of the value is such that E
|
factor is 1 and when the magnitude of the value is such that E
|
||||||
editing is used. However, gfortran compensates for this, and thus
|
editing is used. However, gfortran compensates for this, and thus
|
||||||
|
|
@ -1435,25 +1512,51 @@ set_fnode_default (st_parameter_dt *dtp, fnode *f, int length)
|
||||||
generated both when using F and E editing. */
|
generated both when using F and E editing. */
|
||||||
|
|
||||||
void
|
void
|
||||||
write_real (st_parameter_dt *dtp, const char *source, int length)
|
write_real (st_parameter_dt *dtp, const char *source, int kind)
|
||||||
{
|
{
|
||||||
fnode f ;
|
fnode f ;
|
||||||
int org_scale = dtp->u.p.scale_factor;
|
char buf_stack[BUF_STACK_SZ];
|
||||||
|
char str_buf[BUF_STACK_SZ];
|
||||||
|
char *buffer, *result;
|
||||||
|
size_t buf_size, res_len;
|
||||||
|
int orig_scale = dtp->u.p.scale_factor;
|
||||||
dtp->u.p.scale_factor = 1;
|
dtp->u.p.scale_factor = 1;
|
||||||
set_fnode_default (dtp, &f, length);
|
set_fnode_default (dtp, &f, kind);
|
||||||
write_float (dtp, &f, source , length, 1);
|
|
||||||
dtp->u.p.scale_factor = org_scale;
|
/* Precision for snprintf call. */
|
||||||
|
int precision = get_precision (dtp, &f, source, kind);
|
||||||
|
|
||||||
|
/* String buffer to hold final result. */
|
||||||
|
result = select_string (&f, str_buf, &res_len);
|
||||||
|
|
||||||
|
/* scratch buffer to hold final result. */
|
||||||
|
buffer = select_buffer (precision, buf_stack, &buf_size);
|
||||||
|
|
||||||
|
get_float_string (dtp, &f, source , kind, 1, buffer,
|
||||||
|
precision, buf_size, result, &res_len);
|
||||||
|
write_float_string (dtp, result, res_len);
|
||||||
|
|
||||||
|
dtp->u.p.scale_factor = orig_scale;
|
||||||
|
if (buf_size > BUF_STACK_SZ)
|
||||||
|
free (buffer);
|
||||||
|
if (res_len > BUF_STACK_SZ)
|
||||||
|
free (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Similar to list formatted REAL output, for kPG0 where k > 0 we
|
/* Similar to list formatted REAL output, for kPG0 where k > 0 we
|
||||||
compensate for the extra digit. */
|
compensate for the extra digit. */
|
||||||
|
|
||||||
void
|
void
|
||||||
write_real_g0 (st_parameter_dt *dtp, const char *source, int length, int d)
|
write_real_g0 (st_parameter_dt *dtp, const char *source, int kind, int d)
|
||||||
{
|
{
|
||||||
fnode f;
|
fnode f;
|
||||||
|
char buf_stack[BUF_STACK_SZ];
|
||||||
|
char str_buf[BUF_STACK_SZ];
|
||||||
|
char *buffer, *result;
|
||||||
|
size_t buf_size, res_len;
|
||||||
int comp_d;
|
int comp_d;
|
||||||
set_fnode_default (dtp, &f, length);
|
set_fnode_default (dtp, &f, kind);
|
||||||
|
|
||||||
if (d > 0)
|
if (d > 0)
|
||||||
f.u.real.d = d;
|
f.u.real.d = d;
|
||||||
|
|
||||||
|
|
@ -1464,8 +1567,24 @@ write_real_g0 (st_parameter_dt *dtp, const char *source, int length, int d)
|
||||||
else
|
else
|
||||||
comp_d = 0;
|
comp_d = 0;
|
||||||
dtp->u.p.g0_no_blanks = 1;
|
dtp->u.p.g0_no_blanks = 1;
|
||||||
write_float (dtp, &f, source , length, comp_d);
|
|
||||||
|
/* Precision for snprintf call. */
|
||||||
|
int precision = get_precision (dtp, &f, source, kind);
|
||||||
|
|
||||||
|
/* String buffer to hold final result. */
|
||||||
|
result = select_string (&f, str_buf, &res_len);
|
||||||
|
|
||||||
|
buffer = select_buffer (precision, buf_stack, &buf_size);
|
||||||
|
|
||||||
|
get_float_string (dtp, &f, source , kind, comp_d, buffer,
|
||||||
|
precision, buf_size, result, &res_len);
|
||||||
|
write_float_string (dtp, result, res_len);
|
||||||
|
|
||||||
dtp->u.p.g0_no_blanks = 0;
|
dtp->u.p.g0_no_blanks = 0;
|
||||||
|
if (buf_size > BUF_STACK_SZ)
|
||||||
|
free (buffer);
|
||||||
|
if (res_len > BUF_STACK_SZ)
|
||||||
|
free (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1475,15 +1594,58 @@ write_complex (st_parameter_dt *dtp, const char *source, int kind, size_t size)
|
||||||
char semi_comma =
|
char semi_comma =
|
||||||
dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? ',' : ';';
|
dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? ',' : ';';
|
||||||
|
|
||||||
if (write_char (dtp, '('))
|
/* Set for no blanks so we get a string result with no leading
|
||||||
return;
|
blanks. We will pad left later. */
|
||||||
write_real (dtp, source, kind);
|
dtp->u.p.g0_no_blanks = 1;
|
||||||
|
|
||||||
if (write_char (dtp, semi_comma))
|
fnode f ;
|
||||||
return;
|
char buf_stack[BUF_STACK_SZ];
|
||||||
write_real (dtp, source + size / 2, kind);
|
char str1_buf[BUF_STACK_SZ];
|
||||||
|
char str2_buf[BUF_STACK_SZ];
|
||||||
|
char *buffer, *result1, *result2;
|
||||||
|
size_t buf_size, res_len1, res_len2;
|
||||||
|
int width, lblanks, orig_scale = dtp->u.p.scale_factor;
|
||||||
|
|
||||||
|
dtp->u.p.scale_factor = 1;
|
||||||
|
set_fnode_default (dtp, &f, kind);
|
||||||
|
|
||||||
|
/* Set width for two values, parenthesis, and comma. */
|
||||||
|
width = 2 * f.u.real.w + 3;
|
||||||
|
|
||||||
|
/* Set for no blanks so we get a string result with no leading
|
||||||
|
blanks. We will pad left later. */
|
||||||
|
dtp->u.p.g0_no_blanks = 1;
|
||||||
|
|
||||||
|
/* Precision for snprintf call. */
|
||||||
|
int precision = get_precision (dtp, &f, source, kind);
|
||||||
|
|
||||||
|
/* String buffers to hold final result. */
|
||||||
|
result1 = select_string (&f, str1_buf, &res_len1);
|
||||||
|
result2 = select_string (&f, str2_buf, &res_len2);
|
||||||
|
|
||||||
|
buffer = select_buffer (precision, buf_stack, &buf_size);
|
||||||
|
|
||||||
|
get_float_string (dtp, &f, source , kind, 0, buffer,
|
||||||
|
precision, buf_size, result1, &res_len1);
|
||||||
|
get_float_string (dtp, &f, source + size / 2 , kind, 0, buffer,
|
||||||
|
precision, buf_size, result2, &res_len2);
|
||||||
|
lblanks = width - res_len1 - res_len2 - 3;
|
||||||
|
|
||||||
|
write_x (dtp, lblanks, lblanks);
|
||||||
|
write_char (dtp, '(');
|
||||||
|
write_float_string (dtp, result1, res_len1);
|
||||||
|
write_char (dtp, semi_comma);
|
||||||
|
write_float_string (dtp, result2, res_len2);
|
||||||
write_char (dtp, ')');
|
write_char (dtp, ')');
|
||||||
|
|
||||||
|
dtp->u.p.scale_factor = orig_scale;
|
||||||
|
dtp->u.p.g0_no_blanks = 0;
|
||||||
|
if (buf_size > BUF_STACK_SZ)
|
||||||
|
free (buffer);
|
||||||
|
if (res_len1 > BUF_STACK_SZ)
|
||||||
|
free (result1);
|
||||||
|
if (res_len2 > BUF_STACK_SZ)
|
||||||
|
free (result2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,13 +108,14 @@ determine_precision (st_parameter_dt * dtp, const fnode * f, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Output a real number according to its format which is FMT_G free. */
|
/* Build a real number according to its format which is FMT_G free. */
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
build_float_string (st_parameter_dt *dtp, const fnode *f, char *buffer,
|
||||||
int nprinted, int precision, int sign_bit, bool zero_flag)
|
size_t size, int nprinted, int precision, int sign_bit,
|
||||||
|
bool zero_flag, int npad, char *result, size_t *len)
|
||||||
{
|
{
|
||||||
char *out;
|
char *put;
|
||||||
char *digits;
|
char *digits;
|
||||||
int e, w, d, p, i;
|
int e, w, d, p, i;
|
||||||
char expchar, rchar;
|
char expchar, rchar;
|
||||||
|
|
@ -180,7 +181,6 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
{
|
{
|
||||||
if (p > 0)
|
if (p > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
memmove (digits + nbefore, digits + nbefore + 1, p);
|
memmove (digits + nbefore, digits + nbefore + 1, p);
|
||||||
digits[nbefore + p] = '.';
|
digits[nbefore + p] = '.';
|
||||||
nbefore += p;
|
nbefore += p;
|
||||||
|
|
@ -252,13 +252,13 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
{
|
{
|
||||||
generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
|
generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
|
||||||
"greater than zero in format specifier 'E' or 'D'");
|
"greater than zero in format specifier 'E' or 'D'");
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
if (p <= -d || p >= d + 2)
|
if (p <= -d || p >= d + 2)
|
||||||
{
|
{
|
||||||
generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
|
generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
|
||||||
"out of range in format specifier 'E' or 'D'");
|
"out of range in format specifier 'E' or 'D'");
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!zero_flag)
|
if (!zero_flag)
|
||||||
|
|
@ -547,178 +547,71 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
nblanks = 0;
|
nblanks = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the ouput buffer. */
|
/* Create the final float string. */
|
||||||
out = write_block (dtp, w);
|
*len = w + npad;
|
||||||
if (out == NULL)
|
put = result;
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Check the value fits in the specified field width. */
|
/* Check the value fits in the specified field width. */
|
||||||
if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE))
|
if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE))
|
||||||
{
|
{
|
||||||
if (unlikely (is_char4_unit (dtp)))
|
star_fill (put, *len);
|
||||||
{
|
return;
|
||||||
gfc_char4_t *out4 = (gfc_char4_t *) out;
|
|
||||||
memset4 (out4, '*', w);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
star_fill (out, w);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For internal character(kind=4) units, we duplicate the code used for
|
|
||||||
regular output slightly modified. This needs to be maintained
|
|
||||||
consistent with the regular code that follows this block. */
|
|
||||||
if (unlikely (is_char4_unit (dtp)))
|
|
||||||
{
|
|
||||||
gfc_char4_t *out4 = (gfc_char4_t *) out;
|
|
||||||
/* Pad to full field width. */
|
|
||||||
|
|
||||||
if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
|
|
||||||
{
|
|
||||||
memset4 (out4, ' ', nblanks);
|
|
||||||
out4 += nblanks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Output the initial sign (if any). */
|
|
||||||
if (sign == S_PLUS)
|
|
||||||
*(out4++) = '+';
|
|
||||||
else if (sign == S_MINUS)
|
|
||||||
*(out4++) = '-';
|
|
||||||
|
|
||||||
/* Output an optional leading zero. */
|
|
||||||
if (leadzero)
|
|
||||||
*(out4++) = '0';
|
|
||||||
|
|
||||||
/* Output the part before the decimal point, padding with zeros. */
|
|
||||||
if (nbefore > 0)
|
|
||||||
{
|
|
||||||
if (nbefore > ndigits)
|
|
||||||
{
|
|
||||||
i = ndigits;
|
|
||||||
memcpy4 (out4, digits, i);
|
|
||||||
ndigits = 0;
|
|
||||||
while (i < nbefore)
|
|
||||||
out4[i++] = '0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
i = nbefore;
|
|
||||||
memcpy4 (out4, digits, i);
|
|
||||||
ndigits -= i;
|
|
||||||
}
|
|
||||||
|
|
||||||
digits += i;
|
|
||||||
out4 += nbefore;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Output the decimal point. */
|
|
||||||
*(out4++) = 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. */
|
|
||||||
if (nzero > 0)
|
|
||||||
{
|
|
||||||
for (i = 0; i < nzero; i++)
|
|
||||||
*(out4++) = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Output digits after the decimal point, padding with zeros. */
|
|
||||||
if (nafter > 0)
|
|
||||||
{
|
|
||||||
if (nafter > ndigits)
|
|
||||||
i = ndigits;
|
|
||||||
else
|
|
||||||
i = nafter;
|
|
||||||
|
|
||||||
memcpy4 (out4, digits, i);
|
|
||||||
while (i < nafter)
|
|
||||||
out4[i++] = '0';
|
|
||||||
|
|
||||||
digits += i;
|
|
||||||
ndigits -= i;
|
|
||||||
out4 += nafter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Output the exponent. */
|
|
||||||
if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
|
|
||||||
{
|
|
||||||
if (expchar != ' ')
|
|
||||||
{
|
|
||||||
*(out4++) = expchar;
|
|
||||||
edigits--;
|
|
||||||
}
|
|
||||||
snprintf (buffer, size, "%+0*d", edigits, e);
|
|
||||||
memcpy4 (out4, buffer, edigits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dtp->u.p.no_leading_blank)
|
|
||||||
{
|
|
||||||
out4 += edigits;
|
|
||||||
memset4 (out4, ' ' , nblanks);
|
|
||||||
dtp->u.p.no_leading_blank = 0;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} /* End of character(kind=4) internal unit code. */
|
|
||||||
|
|
||||||
/* Pad to full field width. */
|
/* Pad to full field width. */
|
||||||
|
|
||||||
if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
|
if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
|
||||||
{
|
{
|
||||||
memset (out, ' ', nblanks);
|
memset (put, ' ', nblanks);
|
||||||
out += nblanks;
|
put += nblanks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output the initial sign (if any). */
|
/* Set the initial sign (if any). */
|
||||||
if (sign == S_PLUS)
|
if (sign == S_PLUS)
|
||||||
*(out++) = '+';
|
*(put++) = '+';
|
||||||
else if (sign == S_MINUS)
|
else if (sign == S_MINUS)
|
||||||
*(out++) = '-';
|
*(put++) = '-';
|
||||||
|
|
||||||
/* Output an optional leading zero. */
|
/* Set an optional leading zero. */
|
||||||
if (leadzero)
|
if (leadzero)
|
||||||
*(out++) = '0';
|
*(put++) = '0';
|
||||||
|
|
||||||
/* Output the part before the decimal point, padding with zeros. */
|
/* Set the part before the decimal point, padding with zeros. */
|
||||||
if (nbefore > 0)
|
if (nbefore > 0)
|
||||||
{
|
{
|
||||||
if (nbefore > ndigits)
|
if (nbefore > ndigits)
|
||||||
{
|
{
|
||||||
i = ndigits;
|
i = ndigits;
|
||||||
memcpy (out, digits, i);
|
memcpy (put, digits, i);
|
||||||
ndigits = 0;
|
ndigits = 0;
|
||||||
while (i < nbefore)
|
while (i < nbefore)
|
||||||
out[i++] = '0';
|
put[i++] = '0';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
i = nbefore;
|
i = nbefore;
|
||||||
memcpy (out, digits, i);
|
memcpy (put, digits, i);
|
||||||
ndigits -= i;
|
ndigits -= i;
|
||||||
}
|
}
|
||||||
|
|
||||||
digits += i;
|
digits += i;
|
||||||
out += nbefore;
|
put += nbefore;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output the decimal point. */
|
/* Set the decimal point. */
|
||||||
*(out++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
|
*(put++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
|
||||||
if (ft == FMT_F
|
if (ft == FMT_F
|
||||||
&& (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
|
&& (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_PROCDEFINED))
|
||||||
digits++;
|
digits++;
|
||||||
|
|
||||||
/* Output leading zeros after the decimal point. */
|
/* Set leading zeros after the decimal point. */
|
||||||
if (nzero > 0)
|
if (nzero > 0)
|
||||||
{
|
{
|
||||||
for (i = 0; i < nzero; i++)
|
for (i = 0; i < nzero; i++)
|
||||||
*(out++) = '0';
|
*(put++) = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output digits after the decimal point, padding with zeros. */
|
/* Set digits after the decimal point, padding with zeros. */
|
||||||
if (nafter > 0)
|
if (nafter > 0)
|
||||||
{
|
{
|
||||||
if (nafter > ndigits)
|
if (nafter > ndigits)
|
||||||
|
|
@ -726,44 +619,55 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
|
||||||
else
|
else
|
||||||
i = nafter;
|
i = nafter;
|
||||||
|
|
||||||
memcpy (out, digits, i);
|
memcpy (put, digits, i);
|
||||||
while (i < nafter)
|
while (i < nafter)
|
||||||
out[i++] = '0';
|
put[i++] = '0';
|
||||||
|
|
||||||
digits += i;
|
digits += i;
|
||||||
ndigits -= i;
|
ndigits -= i;
|
||||||
out += nafter;
|
put += nafter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output the exponent. */
|
/* Set the exponent. */
|
||||||
if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
|
if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
|
||||||
{
|
{
|
||||||
if (expchar != ' ')
|
if (expchar != ' ')
|
||||||
{
|
{
|
||||||
*(out++) = expchar;
|
*(put++) = expchar;
|
||||||
edigits--;
|
edigits--;
|
||||||
}
|
}
|
||||||
snprintf (buffer, size, "%+0*d", edigits, e);
|
snprintf (buffer, size, "%+0*d", edigits, e);
|
||||||
memcpy (out, buffer, edigits);
|
memcpy (put, buffer, edigits);
|
||||||
|
put += edigits;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dtp->u.p.no_leading_blank)
|
if (dtp->u.p.no_leading_blank)
|
||||||
{
|
{
|
||||||
out += edigits;
|
memset (put , ' ' , nblanks);
|
||||||
memset( out , ' ' , nblanks );
|
|
||||||
dtp->u.p.no_leading_blank = 0;
|
dtp->u.p.no_leading_blank = 0;
|
||||||
|
put += nblanks;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (npad > 0 && !dtp->u.p.g0_no_blanks)
|
||||||
|
{
|
||||||
|
memset (put , ' ' , npad);
|
||||||
|
put += npad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL terminate the string. */
|
||||||
|
*put = '\0';
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write "Infinite" or "Nan" as appropriate for the given format. */
|
/* Write "Infinite" or "Nan" as appropriate for the given format. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit)
|
build_infnan_string (st_parameter_dt *dtp, const fnode *f, int isnan_flag,
|
||||||
|
int sign_bit, char *p, size_t *len)
|
||||||
{
|
{
|
||||||
char * p, fin;
|
char fin;
|
||||||
int nb = 0;
|
int nb = 0;
|
||||||
sign_t sign;
|
sign_t sign;
|
||||||
int mark;
|
int mark;
|
||||||
|
|
@ -774,6 +678,7 @@ write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit
|
||||||
mark = (sign == S_PLUS || sign == S_MINUS) ? 8 : 7;
|
mark = (sign == S_PLUS || sign == S_MINUS) ? 8 : 7;
|
||||||
|
|
||||||
nb = f->u.real.w;
|
nb = f->u.real.w;
|
||||||
|
*len = nb;
|
||||||
|
|
||||||
/* If the field width is zero, the processor must select a width
|
/* If the field width is zero, the processor must select a width
|
||||||
not zero. 4 is chosen to allow output of '-Inf' or '+Inf' */
|
not zero. 4 is chosen to allow output of '-Inf' or '+Inf' */
|
||||||
|
|
@ -784,29 +689,17 @@ write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit
|
||||||
nb = 3;
|
nb = 3;
|
||||||
else
|
else
|
||||||
nb = (sign == S_PLUS || sign == S_MINUS) ? 4 : 3;
|
nb = (sign == S_PLUS || sign == S_MINUS) ? 4 : 3;
|
||||||
|
*len = nb;
|
||||||
}
|
}
|
||||||
p = write_block (dtp, nb);
|
|
||||||
if (p == NULL)
|
p[*len] = '\0';
|
||||||
return;
|
|
||||||
if (nb < 3)
|
if (nb < 3)
|
||||||
{
|
{
|
||||||
if (unlikely (is_char4_unit (dtp)))
|
memset (p, '*', nb);
|
||||||
{
|
|
||||||
gfc_char4_t *p4 = (gfc_char4_t *) p;
|
|
||||||
memset4 (p4, '*', nb);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memset (p, '*', nb);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely (is_char4_unit (dtp)))
|
memset(p, ' ', nb);
|
||||||
{
|
|
||||||
gfc_char4_t *p4 = (gfc_char4_t *) p;
|
|
||||||
memset4 (p4, ' ', nb);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memset(p, ' ', nb);
|
|
||||||
|
|
||||||
if (!isnan_flag)
|
if (!isnan_flag)
|
||||||
{
|
{
|
||||||
|
|
@ -816,13 +709,7 @@ write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit
|
||||||
insufficient room to output '-Inf', so output asterisks */
|
insufficient room to output '-Inf', so output asterisks */
|
||||||
if (nb == 3)
|
if (nb == 3)
|
||||||
{
|
{
|
||||||
if (unlikely (is_char4_unit (dtp)))
|
memset (p, '*', nb);
|
||||||
{
|
|
||||||
gfc_char4_t *p4 = (gfc_char4_t *) p;
|
|
||||||
memset4 (p4, '*', nb);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memset (p, '*', nb);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* The negative sign is mandatory */
|
/* The negative sign is mandatory */
|
||||||
|
|
@ -833,30 +720,6 @@ write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit
|
||||||
consistency */
|
consistency */
|
||||||
fin = '+';
|
fin = '+';
|
||||||
|
|
||||||
if (unlikely (is_char4_unit (dtp)))
|
|
||||||
{
|
|
||||||
gfc_char4_t *p4 = (gfc_char4_t *) p;
|
|
||||||
|
|
||||||
if (nb > mark)
|
|
||||||
/* We have room, so output 'Infinity' */
|
|
||||||
memcpy4 (p4 + nb - 8, "Infinity", 8);
|
|
||||||
else
|
|
||||||
/* For the case of width equals mark, there is not enough room
|
|
||||||
for the sign and 'Infinity' so we go with 'Inf' */
|
|
||||||
memcpy4 (p4 + nb - 3, "Inf", 3);
|
|
||||||
|
|
||||||
if (sign == S_PLUS || sign == S_MINUS)
|
|
||||||
{
|
|
||||||
if (nb < 9 && nb > 3)
|
|
||||||
/* Put the sign in front of Inf */
|
|
||||||
p4[nb - 4] = (gfc_char4_t) fin;
|
|
||||||
else if (nb > 8)
|
|
||||||
/* Put the sign in front of Infinity */
|
|
||||||
p4[nb - 9] = (gfc_char4_t) fin;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nb > mark)
|
if (nb > mark)
|
||||||
/* We have room, so output 'Infinity' */
|
/* We have room, so output 'Infinity' */
|
||||||
memcpy(p + nb - 8, "Infinity", 8);
|
memcpy(p + nb - 8, "Infinity", 8);
|
||||||
|
|
@ -874,16 +737,7 @@ write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
memcpy(p + nb - 3, "NaN", 3);
|
||||||
if (unlikely (is_char4_unit (dtp)))
|
|
||||||
{
|
|
||||||
gfc_char4_t *p4 = (gfc_char4_t *) p;
|
|
||||||
memcpy4 (p4 + nb - 3, "NaN", 3);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memcpy(p + nb - 3, "NaN", 3);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -916,7 +770,7 @@ CALCULATE_EXP(16)
|
||||||
#undef CALCULATE_EXP
|
#undef CALCULATE_EXP
|
||||||
|
|
||||||
|
|
||||||
/* Define a macro to build code for write_float. */
|
/* Define macros to build code for format_float. */
|
||||||
|
|
||||||
/* Note: Before output_float is called, snprintf is used to print to buffer the
|
/* Note: Before output_float is called, snprintf is used to print to buffer the
|
||||||
number in the format +D.DDDDe+ddd.
|
number in the format +D.DDDDe+ddd.
|
||||||
|
|
@ -941,196 +795,35 @@ CALCULATE_EXP(16)
|
||||||
|
|
||||||
#define DTOA(suff,prec,val) TOKENPASTE(DTOA2,suff)(prec,val)
|
#define DTOA(suff,prec,val) TOKENPASTE(DTOA2,suff)(prec,val)
|
||||||
|
|
||||||
#define DTOA2(prec,val) \
|
#define DTOA2(prec,val) \
|
||||||
snprintf (buffer, size, "%+-#.*e", (prec), (val))
|
snprintf (buffer, size, "%+-#.*e", (prec), (val))
|
||||||
|
|
||||||
#define DTOA2L(prec,val) \
|
#define DTOA2L(prec,val) \
|
||||||
snprintf (buffer, size, "%+-#.*Le", (prec), (val))
|
snprintf (buffer, size, "%+-#.*Le", (prec), (val))
|
||||||
|
|
||||||
|
|
||||||
#if defined(GFC_REAL_16_IS_FLOAT128)
|
#if defined(GFC_REAL_16_IS_FLOAT128)
|
||||||
#define DTOA2Q(prec,val) \
|
#define DTOA2Q(prec,val) \
|
||||||
quadmath_snprintf (buffer, size, "%+-#.*Qe", (prec), (val))
|
quadmath_snprintf (buffer, size, "%+-#.*Qe", (prec), (val))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FDTOA(suff,prec,val) TOKENPASTE(FDTOA2,suff)(prec,val)
|
#define FDTOA(suff,prec,val) TOKENPASTE(FDTOA2,suff)(prec,val)
|
||||||
|
|
||||||
/* For F format, we print to the buffer with f format. */
|
/* For F format, we print to the buffer with f format. */
|
||||||
#define FDTOA2(prec,val) \
|
#define FDTOA2(prec,val) \
|
||||||
snprintf (buffer, size, "%+-#.*f", (prec), (val))
|
snprintf (buffer, size, "%+-#.*f", (prec), (val))
|
||||||
|
|
||||||
#define FDTOA2L(prec,val) \
|
#define FDTOA2L(prec,val) \
|
||||||
snprintf (buffer, size, "%+-#.*Lf", (prec), (val))
|
snprintf (buffer, size, "%+-#.*Lf", (prec), (val))
|
||||||
|
|
||||||
|
|
||||||
#if defined(GFC_REAL_16_IS_FLOAT128)
|
#if defined(GFC_REAL_16_IS_FLOAT128)
|
||||||
#define FDTOA2Q(prec,val) \
|
#define FDTOA2Q(prec,val) \
|
||||||
quadmath_snprintf (buffer, size, "%+-#.*Qf", \
|
quadmath_snprintf (buffer, size, "%+-#.*Qf", \
|
||||||
(prec), (val))
|
(prec), (val))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
|
|
||||||
|
|
||||||
Data Magnitude Equivalent Conversion
|
|
||||||
0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
|
|
||||||
m = 0 F(w-n).(d-1), n' '
|
|
||||||
0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
|
|
||||||
1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
|
|
||||||
10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
|
|
||||||
................ ..........
|
|
||||||
10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
|
|
||||||
m >= 10**d-0.5 Ew.d[Ee]
|
|
||||||
|
|
||||||
notes: for Gw.d , n' ' means 4 blanks
|
|
||||||
for Gw.dEe, n' ' means e+2 blanks
|
|
||||||
for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
|
|
||||||
the asm volatile is required for 32-bit x86 platforms. */
|
|
||||||
|
|
||||||
#define OUTPUT_FLOAT_FMT_G(x,y) \
|
|
||||||
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 comp_d) \
|
|
||||||
{ \
|
|
||||||
int e = f->u.real.e;\
|
|
||||||
int d = f->u.real.d;\
|
|
||||||
int w = f->u.real.w;\
|
|
||||||
fnode newf;\
|
|
||||||
GFC_REAL_ ## x exp_d, r = 0.5, r_sc;\
|
|
||||||
int low, high, mid;\
|
|
||||||
int ubound, lbound;\
|
|
||||||
char *p, pad = ' ';\
|
|
||||||
int save_scale_factor, nb = 0;\
|
|
||||||
bool result;\
|
|
||||||
int nprinted, precision;\
|
|
||||||
volatile GFC_REAL_ ## x temp;\
|
|
||||||
\
|
|
||||||
save_scale_factor = dtp->u.p.scale_factor;\
|
|
||||||
\
|
|
||||||
switch (dtp->u.p.current_unit->round_status)\
|
|
||||||
{\
|
|
||||||
case ROUND_ZERO:\
|
|
||||||
r = sign_bit ? 1.0 : 0.0;\
|
|
||||||
break;\
|
|
||||||
case ROUND_UP:\
|
|
||||||
r = 1.0;\
|
|
||||||
break;\
|
|
||||||
case ROUND_DOWN:\
|
|
||||||
r = 0.0;\
|
|
||||||
break;\
|
|
||||||
default:\
|
|
||||||
break;\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
exp_d = calculate_exp_ ## x (d);\
|
|
||||||
r_sc = (1 - r / exp_d);\
|
|
||||||
temp = 0.1 * r_sc;\
|
|
||||||
if ((m > 0.0 && ((m < temp) || (r >= (exp_d - m))))\
|
|
||||||
|| ((m == 0.0) && !(compile_options.allow_std\
|
|
||||||
& (GFC_STD_F2003 | GFC_STD_F2008)))\
|
|
||||||
|| d == 0)\
|
|
||||||
{ \
|
|
||||||
newf.format = FMT_E;\
|
|
||||||
newf.u.real.w = w;\
|
|
||||||
newf.u.real.d = d - comp_d;\
|
|
||||||
newf.u.real.e = e;\
|
|
||||||
nb = 0;\
|
|
||||||
precision = determine_precision (dtp, &newf, x);\
|
|
||||||
nprinted = DTOA(y,precision,m); \
|
|
||||||
goto finish;\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
mid = 0;\
|
|
||||||
low = 0;\
|
|
||||||
high = d + 1;\
|
|
||||||
lbound = 0;\
|
|
||||||
ubound = d + 1;\
|
|
||||||
\
|
|
||||||
while (low <= high)\
|
|
||||||
{ \
|
|
||||||
mid = (low + high) / 2;\
|
|
||||||
\
|
|
||||||
temp = (calculate_exp_ ## x (mid - 1) * r_sc);\
|
|
||||||
\
|
|
||||||
if (m < temp)\
|
|
||||||
{ \
|
|
||||||
ubound = mid;\
|
|
||||||
if (ubound == lbound + 1)\
|
|
||||||
break;\
|
|
||||||
high = mid - 1;\
|
|
||||||
}\
|
|
||||||
else if (m > temp)\
|
|
||||||
{ \
|
|
||||||
lbound = mid;\
|
|
||||||
if (ubound == lbound + 1)\
|
|
||||||
{ \
|
|
||||||
mid ++;\
|
|
||||||
break;\
|
|
||||||
}\
|
|
||||||
low = mid + 1;\
|
|
||||||
}\
|
|
||||||
else\
|
|
||||||
{\
|
|
||||||
mid++;\
|
|
||||||
break;\
|
|
||||||
}\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
nb = e <= 0 ? 4 : e + 2;\
|
|
||||||
nb = nb >= w ? w - 1 : nb;\
|
|
||||||
newf.format = FMT_F;\
|
|
||||||
newf.u.real.w = w - nb;\
|
|
||||||
newf.u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
|
|
||||||
dtp->u.p.scale_factor = 0;\
|
|
||||||
precision = determine_precision (dtp, &newf, x); \
|
|
||||||
nprinted = FDTOA(y,precision,m); \
|
|
||||||
\
|
|
||||||
finish:\
|
|
||||||
result = output_float (dtp, &newf, buffer, size, nprinted, precision,\
|
|
||||||
sign_bit, zero_flag);\
|
|
||||||
dtp->u.p.scale_factor = save_scale_factor;\
|
|
||||||
\
|
|
||||||
\
|
|
||||||
if (nb > 0 && !dtp->u.p.g0_no_blanks)\
|
|
||||||
{\
|
|
||||||
p = write_block (dtp, nb);\
|
|
||||||
if (p == NULL)\
|
|
||||||
return;\
|
|
||||||
if (!result)\
|
|
||||||
pad = '*';\
|
|
||||||
if (unlikely (is_char4_unit (dtp)))\
|
|
||||||
{\
|
|
||||||
gfc_char4_t *p4 = (gfc_char4_t *) p;\
|
|
||||||
memset4 (p4, pad, nb);\
|
|
||||||
}\
|
|
||||||
else \
|
|
||||||
memset (p, pad, nb);\
|
|
||||||
}\
|
|
||||||
}\
|
|
||||||
|
|
||||||
OUTPUT_FLOAT_FMT_G(4,)
|
|
||||||
|
|
||||||
OUTPUT_FLOAT_FMT_G(8,)
|
|
||||||
|
|
||||||
#ifdef HAVE_GFC_REAL_10
|
|
||||||
OUTPUT_FLOAT_FMT_G(10,L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_GFC_REAL_16
|
|
||||||
# ifdef GFC_REAL_16_IS_FLOAT128
|
|
||||||
OUTPUT_FLOAT_FMT_G(16,Q)
|
|
||||||
#else
|
|
||||||
OUTPUT_FLOAT_FMT_G(16,L)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef OUTPUT_FLOAT_FMT_G
|
|
||||||
|
|
||||||
|
|
||||||
/* EN format is tricky since the number of significant digits depends
|
/* EN format is tricky since the number of significant digits depends
|
||||||
on the magnitude. Solve it by first printing a temporary value and
|
on the magnitude. Solve it by first printing a temporary value and
|
||||||
figure out the number of significant digits from the printed
|
figure out the number of significant digits from the printed
|
||||||
|
|
@ -1144,7 +837,6 @@ OUTPUT_FLOAT_FMT_G(16,L)
|
||||||
are correctly rounded respectively to 1.0...0*10.0*(3*(n+1)),
|
are correctly rounded respectively to 1.0...0*10.0*(3*(n+1)),
|
||||||
100.0...0*10.0*(3*n), and 10.0...0*10.0*(3*n), where 0...0
|
100.0...0*10.0*(3*n), and 10.0...0*10.0*(3*n), where 0...0
|
||||||
represents d zeroes, by the lines 279 to 297. */
|
represents d zeroes, by the lines 279 to 297. */
|
||||||
|
|
||||||
#define EN_PREC(x,y)\
|
#define EN_PREC(x,y)\
|
||||||
{\
|
{\
|
||||||
volatile GFC_REAL_ ## x tmp, one = 1.0;\
|
volatile GFC_REAL_ ## x tmp, one = 1.0;\
|
||||||
|
|
@ -1156,7 +848,7 @@ OUTPUT_FLOAT_FMT_G(16,L)
|
||||||
if (buffer[1] == '1')\
|
if (buffer[1] == '1')\
|
||||||
{\
|
{\
|
||||||
tmp = (calculate_exp_ ## x (-e)) * tmp;\
|
tmp = (calculate_exp_ ## x (-e)) * tmp;\
|
||||||
tmp = one - (tmp < 0 ? -tmp : tmp); \
|
tmp = one - (tmp < 0 ? -tmp : tmp);\
|
||||||
if (tmp > 0)\
|
if (tmp > 0)\
|
||||||
e = e - 1;\
|
e = e - 1;\
|
||||||
}\
|
}\
|
||||||
|
|
@ -1216,87 +908,175 @@ determine_en_precision (st_parameter_dt *dtp, const fnode *f,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define WRITE_FLOAT(x,y)\
|
/* Generate corresponding I/O format. and output.
|
||||||
|
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:
|
||||||
|
|
||||||
|
Data Magnitude Equivalent Conversion
|
||||||
|
0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
|
||||||
|
m = 0 F(w-n).(d-1), n' '
|
||||||
|
0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
|
||||||
|
1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
|
||||||
|
10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
|
||||||
|
................ ..........
|
||||||
|
10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
|
||||||
|
m >= 10**d-0.5 Ew.d[Ee]
|
||||||
|
|
||||||
|
notes: for Gw.d , n' ' means 4 blanks
|
||||||
|
for Gw.dEe, n' ' means e+2 blanks
|
||||||
|
for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
|
||||||
|
the asm volatile is required for 32-bit x86 platforms. */
|
||||||
|
#define FORMAT_FLOAT(x,y)\
|
||||||
{\
|
{\
|
||||||
GFC_REAL_ ## x tmp;\
|
int npad = 0;\
|
||||||
tmp = * (GFC_REAL_ ## x *)source;\
|
GFC_REAL_ ## x m;\
|
||||||
sign_bit = signbit (tmp);\
|
m = * (GFC_REAL_ ## x *)source;\
|
||||||
if (!isfinite (tmp))\
|
sign_bit = signbit (m);\
|
||||||
{ \
|
if (!isfinite (m))\
|
||||||
write_infnan (dtp, f, isnan (tmp), sign_bit);\
|
{ \
|
||||||
return;\
|
build_infnan_string (dtp, f, isnan (m), sign_bit, result, res_len);\
|
||||||
}\
|
return;\
|
||||||
tmp = sign_bit ? -tmp : tmp;\
|
}\
|
||||||
zero_flag = (tmp == 0.0);\
|
m = sign_bit ? -m : m;\
|
||||||
if (f->format == FMT_G)\
|
zero_flag = (m == 0.0);\
|
||||||
output_float_FMT_G_ ## x (dtp, f, tmp, buffer, size, sign_bit, \
|
if (f->format == FMT_G)\
|
||||||
zero_flag, comp_d);\
|
{\
|
||||||
else\
|
int e = f->u.real.e;\
|
||||||
{\
|
int d = f->u.real.d;\
|
||||||
if (f->format == FMT_F)\
|
int w = f->u.real.w;\
|
||||||
nprinted = FDTOA(y,precision,tmp); \
|
fnode newf;\
|
||||||
else\
|
GFC_REAL_ ## x exp_d, r = 0.5, r_sc;\
|
||||||
nprinted = DTOA(y,precision,tmp); \
|
int low, high, mid;\
|
||||||
output_float (dtp, f, buffer, size, nprinted, precision,\
|
int ubound, lbound;\
|
||||||
sign_bit, zero_flag);\
|
int save_scale_factor;\
|
||||||
}\
|
volatile GFC_REAL_ ## x temp;\
|
||||||
|
save_scale_factor = dtp->u.p.scale_factor;\
|
||||||
|
switch (dtp->u.p.current_unit->round_status)\
|
||||||
|
{\
|
||||||
|
case ROUND_ZERO:\
|
||||||
|
r = sign_bit ? 1.0 : 0.0;\
|
||||||
|
break;\
|
||||||
|
case ROUND_UP:\
|
||||||
|
r = 1.0;\
|
||||||
|
break;\
|
||||||
|
case ROUND_DOWN:\
|
||||||
|
r = 0.0;\
|
||||||
|
break;\
|
||||||
|
default:\
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
exp_d = calculate_exp_ ## x (d);\
|
||||||
|
r_sc = (1 - r / exp_d);\
|
||||||
|
temp = 0.1 * r_sc;\
|
||||||
|
if ((m > 0.0 && ((m < temp) || (r >= (exp_d - m))))\
|
||||||
|
|| ((m == 0.0) && !(compile_options.allow_std\
|
||||||
|
& (GFC_STD_F2003 | GFC_STD_F2008)))\
|
||||||
|
|| d == 0)\
|
||||||
|
{ \
|
||||||
|
newf.format = FMT_E;\
|
||||||
|
newf.u.real.w = w;\
|
||||||
|
newf.u.real.d = d - comp_d;\
|
||||||
|
newf.u.real.e = e;\
|
||||||
|
npad = 0;\
|
||||||
|
precision = determine_precision (dtp, &newf, x);\
|
||||||
|
nprinted = DTOA(y,precision,m);\
|
||||||
|
}\
|
||||||
|
else \
|
||||||
|
{\
|
||||||
|
mid = 0;\
|
||||||
|
low = 0;\
|
||||||
|
high = d + 1;\
|
||||||
|
lbound = 0;\
|
||||||
|
ubound = d + 1;\
|
||||||
|
while (low <= high)\
|
||||||
|
{\
|
||||||
|
mid = (low + high) / 2;\
|
||||||
|
temp = (calculate_exp_ ## x (mid - 1) * r_sc);\
|
||||||
|
if (m < temp)\
|
||||||
|
{ \
|
||||||
|
ubound = mid;\
|
||||||
|
if (ubound == lbound + 1)\
|
||||||
|
break;\
|
||||||
|
high = mid - 1;\
|
||||||
|
}\
|
||||||
|
else if (m > temp)\
|
||||||
|
{ \
|
||||||
|
lbound = mid;\
|
||||||
|
if (ubound == lbound + 1)\
|
||||||
|
{ \
|
||||||
|
mid ++;\
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
low = mid + 1;\
|
||||||
|
}\
|
||||||
|
else\
|
||||||
|
{\
|
||||||
|
mid++;\
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
npad = e <= 0 ? 4 : e + 2;\
|
||||||
|
npad = npad >= w ? w - 1 : npad;\
|
||||||
|
npad = dtp->u.p.g0_no_blanks ? 0 : npad;\
|
||||||
|
newf.format = FMT_F;\
|
||||||
|
newf.u.real.w = w - npad;\
|
||||||
|
newf.u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
|
||||||
|
dtp->u.p.scale_factor = 0;\
|
||||||
|
precision = determine_precision (dtp, &newf, x);\
|
||||||
|
nprinted = FDTOA(y,precision,m);\
|
||||||
|
}\
|
||||||
|
build_float_string (dtp, &newf, buffer, size, nprinted, precision,\
|
||||||
|
sign_bit, zero_flag, npad, result, res_len);\
|
||||||
|
dtp->u.p.scale_factor = save_scale_factor;\
|
||||||
|
}\
|
||||||
|
else\
|
||||||
|
{\
|
||||||
|
if (f->format == FMT_F)\
|
||||||
|
nprinted = FDTOA(y,precision,m);\
|
||||||
|
else\
|
||||||
|
nprinted = DTOA(y,precision,m);\
|
||||||
|
build_float_string (dtp, f, buffer, size, nprinted, precision,\
|
||||||
|
sign_bit, zero_flag, npad, result, res_len);\
|
||||||
|
}\
|
||||||
}\
|
}\
|
||||||
|
|
||||||
/* Output a real number according to its format. */
|
/* Output a real number according to its format. */
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
write_float (st_parameter_dt *dtp, const fnode *f, const char *source, \
|
get_float_string (st_parameter_dt *dtp, const fnode *f, const char *source,
|
||||||
int len, int comp_d)
|
int kind, int comp_d, char *buffer, int precision,
|
||||||
|
size_t size, char *result, size_t *res_len)
|
||||||
{
|
{
|
||||||
int sign_bit, nprinted;
|
int sign_bit, nprinted;
|
||||||
int precision; /* Precision for snprintf call. */
|
|
||||||
bool zero_flag;
|
bool zero_flag;
|
||||||
|
|
||||||
if (f->format != FMT_EN)
|
switch (kind)
|
||||||
precision = determine_precision (dtp, f, len);
|
|
||||||
else
|
|
||||||
precision = determine_en_precision (dtp, f, source, len);
|
|
||||||
|
|
||||||
/* 4932 is the maximum exponent of long double and quad precision, 3
|
|
||||||
extra characters for the sign, the decimal point, and the
|
|
||||||
trailing null, and finally some extra digits depending on the
|
|
||||||
requested precision. */
|
|
||||||
const size_t size = 4932 + 3 + precision;
|
|
||||||
#define BUF_STACK_SZ 5000
|
|
||||||
char buf_stack[BUF_STACK_SZ];
|
|
||||||
char *buffer;
|
|
||||||
if (size > BUF_STACK_SZ)
|
|
||||||
buffer = xmalloc (size);
|
|
||||||
else
|
|
||||||
buffer = buf_stack;
|
|
||||||
|
|
||||||
switch (len)
|
|
||||||
{
|
{
|
||||||
case 4:
|
case 4:
|
||||||
WRITE_FLOAT(4,)
|
FORMAT_FLOAT(4,)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 8:
|
case 8:
|
||||||
WRITE_FLOAT(8,)
|
FORMAT_FLOAT(8,)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef HAVE_GFC_REAL_10
|
#ifdef HAVE_GFC_REAL_10
|
||||||
case 10:
|
case 10:
|
||||||
WRITE_FLOAT(10,L)
|
FORMAT_FLOAT(10,L)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_GFC_REAL_16
|
#ifdef HAVE_GFC_REAL_16
|
||||||
case 16:
|
case 16:
|
||||||
# ifdef GFC_REAL_16_IS_FLOAT128
|
# ifdef GFC_REAL_16_IS_FLOAT128
|
||||||
WRITE_FLOAT(16,Q)
|
FORMAT_FLOAT(16,Q)
|
||||||
# else
|
# else
|
||||||
WRITE_FLOAT(16,L)
|
FORMAT_FLOAT(16,L)
|
||||||
# endif
|
# endif
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
internal_error (NULL, "bad real kind");
|
internal_error (NULL, "bad real kind");
|
||||||
}
|
}
|
||||||
if (size > BUF_STACK_SZ)
|
return;
|
||||||
free (buffer);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue