Commit 379924dd by Jerry DeLisle

re PR libfortran/35862 ([F2003] Implement new rounding modes for run time)

2009-09-28  Jerry DeLisle  <jvdelisle@gcc.gnu.org>

	PR libgfortran/35862
	* io.h (gfc_unit): Add round_status.
	(format_token): Add enumerators for rounding format specifiers.
	* transfer.c (round_opt): New options table.
	(formatted_transfer_scalar_read): Add set round_status for each rounding
	format token. (formatted_transfer_scalar_write): Likewise.
	* format.c (format_lex): Tokenize the rounding format specifiers.
	(parse_format_list): Parse the rounding format specifiers.
	* write_float.def (outout_float): Modify rounding code to use new
	variable rchar to set the appropriate rounding. Fix some whitespace.
	* unit.c (get_internal_unit): Initialize rounding mode for internal
	units. (init_units): Likewise.

From-SVN: r152263
parent f2a71504
2009-09-28 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libgfortran/35862
* io.h (gfc_unit): Add round_status.
(format_token): Add enumerators for rounding format specifiers.
* transfer.c (round_opt): New options table.
(formatted_transfer_scalar_read): Add set round_status for each rounding
format token. (formatted_transfer_scalar_write): Likewise.
* format.c (format_lex): Tokenize the rounding format specifiers.
(parse_format_list): Parse the rounding format specifiers.
* write_float.def (outout_float): Modify rounding code to use new
variable rchar to set the appropriate rounding. Fix some whitespace.
* unit.c (get_internal_unit): Initialize rounding mode for internal
units. (init_units): Likewise.
2009-09-19 Iain Sandoe <iain.sandoe@sandoe-acoustics.co.uk> 2009-09-19 Iain Sandoe <iain.sandoe@sandoe-acoustics.co.uk>
* configure.ac: Check for GFORTRAN_C99_1.1 funcs in OS libm. * configure.ac: Check for GFORTRAN_C99_1.1 funcs in OS libm.
......
...@@ -564,6 +564,34 @@ format_lex (format_data *fmt) ...@@ -564,6 +564,34 @@ format_lex (format_data *fmt)
} }
break; break;
case 'R':
switch (next_char (fmt, 0))
{
case 'C':
token = FMT_RC;
break;
case 'D':
token = FMT_RD;
break;
case 'N':
token = FMT_RN;
break;
case 'P':
token = FMT_RP;
break;
case 'U':
token = FMT_RU;
break;
case 'Z':
token = FMT_RZ;
break;
default:
unget_char (fmt);
token = FMT_UNKNOWN;
break;
}
break;
case -1: case -1:
token = FMT_END; token = FMT_END;
break; break;
...@@ -713,6 +741,18 @@ parse_format_list (st_parameter_dt *dtp, bool *save_ok) ...@@ -713,6 +741,18 @@ parse_format_list (st_parameter_dt *dtp, bool *save_ok)
tail->u.string.length = fmt->value; tail->u.string.length = fmt->value;
tail->repeat = 1; tail->repeat = 1;
goto optional_comma; goto optional_comma;
case FMT_RC:
case FMT_RD:
case FMT_RN:
case FMT_RP:
case FMT_RU:
case FMT_RZ:
notify_std (&dtp->common, GFC_STD_F2003, "Fortran 2003: Round "
"descriptor not allowed");
get_fnode (fmt, &head, &tail, t);
tail->repeat = 1;
goto between_desc;
case FMT_DC: case FMT_DC:
case FMT_DP: case FMT_DP:
......
...@@ -602,6 +602,7 @@ typedef struct gfc_unit ...@@ -602,6 +602,7 @@ typedef struct gfc_unit
unit_pad pad_status; unit_pad pad_status;
unit_decimal decimal_status; unit_decimal decimal_status;
unit_delim delim_status; unit_delim delim_status;
unit_round round_status;
/* recl -- Record length of the file. /* recl -- Record length of the file.
last_record -- Last record number read or written last_record -- Last record number read or written
...@@ -654,7 +655,7 @@ typedef enum ...@@ -654,7 +655,7 @@ typedef enum
FMT_LPAREN, FMT_RPAREN, FMT_X, FMT_S, FMT_SS, FMT_SP, FMT_STRING, FMT_LPAREN, FMT_RPAREN, FMT_X, FMT_S, FMT_SS, FMT_SP, FMT_STRING,
FMT_BADSTRING, FMT_P, FMT_I, FMT_B, FMT_BN, FMT_BZ, FMT_O, FMT_Z, FMT_F, FMT_BADSTRING, FMT_P, FMT_I, FMT_B, FMT_BN, FMT_BZ, FMT_O, FMT_Z, FMT_F,
FMT_E, FMT_EN, FMT_ES, FMT_G, FMT_L, FMT_A, FMT_D, FMT_H, FMT_END, FMT_DC, FMT_E, FMT_EN, FMT_ES, FMT_G, FMT_L, FMT_A, FMT_D, FMT_H, FMT_END, FMT_DC,
FMT_DP, FMT_STAR FMT_DP, FMT_STAR, FMT_RC, FMT_RD, FMT_RN, FMT_RP, FMT_RU, FMT_RZ
} }
format_token; format_token;
......
...@@ -101,6 +101,16 @@ static const st_option decimal_opt[] = { ...@@ -101,6 +101,16 @@ static const st_option decimal_opt[] = {
{NULL, 0} {NULL, 0}
}; };
static const st_option round_opt[] = {
{"up", ROUND_UP},
{"down", ROUND_DOWN},
{"zero", ROUND_ZERO},
{"nearest", ROUND_NEAREST},
{"compatible", ROUND_COMPATIBLE},
{"processor_defined", ROUND_PROCDEFINED},
{NULL, 0}
};
static const st_option sign_opt[] = { static const st_option sign_opt[] = {
{"plus", SIGN_SP}, {"plus", SIGN_SP},
...@@ -1202,6 +1212,36 @@ formatted_transfer_scalar_read (st_parameter_dt *dtp, bt type, void *p, int kind ...@@ -1202,6 +1212,36 @@ formatted_transfer_scalar_read (st_parameter_dt *dtp, bt type, void *p, int kind
consume_data_flag = 0; consume_data_flag = 0;
dtp->u.p.current_unit->decimal_status = DECIMAL_POINT; dtp->u.p.current_unit->decimal_status = DECIMAL_POINT;
break; break;
case FMT_RC:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE;
break;
case FMT_RD:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_DOWN;
break;
case FMT_RN:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_NEAREST;
break;
case FMT_RP:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED;
break;
case FMT_RU:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_UP;
break;
case FMT_RZ:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_ZERO;
break;
case FMT_P: case FMT_P:
consume_data_flag = 0; consume_data_flag = 0;
...@@ -1566,6 +1606,36 @@ formatted_transfer_scalar_write (st_parameter_dt *dtp, bt type, void *p, int kin ...@@ -1566,6 +1606,36 @@ formatted_transfer_scalar_write (st_parameter_dt *dtp, bt type, void *p, int kin
dtp->u.p.current_unit->decimal_status = DECIMAL_POINT; dtp->u.p.current_unit->decimal_status = DECIMAL_POINT;
break; break;
case FMT_RC:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE;
break;
case FMT_RD:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_DOWN;
break;
case FMT_RN:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_NEAREST;
break;
case FMT_RP:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED;
break;
case FMT_RU:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_UP;
break;
case FMT_RZ:
consume_data_flag = 0;
dtp->u.p.current_unit->round_status = ROUND_ZERO;
break;
case FMT_P: case FMT_P:
consume_data_flag = 0; consume_data_flag = 0;
dtp->u.p.scale_factor = f->u.k; dtp->u.p.scale_factor = f->u.k;
...@@ -2252,6 +2322,16 @@ data_transfer_init (st_parameter_dt *dtp, int read_flag) ...@@ -2252,6 +2322,16 @@ data_transfer_init (st_parameter_dt *dtp, int read_flag)
if (dtp->u.p.current_unit->decimal_status == DECIMAL_UNSPECIFIED) if (dtp->u.p.current_unit->decimal_status == DECIMAL_UNSPECIFIED)
dtp->u.p.current_unit->decimal_status = dtp->u.p.current_unit->flags.decimal; dtp->u.p.current_unit->decimal_status = dtp->u.p.current_unit->flags.decimal;
/* Check the round mode. */
dtp->u.p.current_unit->round_status
= !(cf & IOPARM_DT_HAS_ROUND) ? ROUND_UNSPECIFIED :
find_option (&dtp->common, dtp->round, dtp->round_len,
round_opt, "Bad ROUND parameter in data transfer "
"statement");
if (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED)
dtp->u.p.current_unit->round_status = dtp->u.p.current_unit->flags.round;
/* Check the sign mode. */ /* Check the sign mode. */
dtp->u.p.sign_status dtp->u.p.sign_status
= !(cf & IOPARM_DT_HAS_SIGN) ? SIGN_UNSPECIFIED : = !(cf & IOPARM_DT_HAS_SIGN) ? SIGN_UNSPECIFIED :
......
...@@ -441,6 +441,7 @@ get_internal_unit (st_parameter_dt *dtp) ...@@ -441,6 +441,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;
/* Initialize the data transfer parameters. */ /* Initialize the data transfer parameters. */
...@@ -531,6 +532,7 @@ init_units (void) ...@@ -531,6 +532,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->recl = options.default_recl; u->recl = options.default_recl;
u->endfile = NO_ENDFILE; u->endfile = NO_ENDFILE;
...@@ -560,6 +562,7 @@ init_units (void) ...@@ -560,6 +562,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->recl = options.default_recl; u->recl = options.default_recl;
u->endfile = AT_ENDFILE; u->endfile = AT_ENDFILE;
...@@ -589,6 +592,7 @@ init_units (void) ...@@ -589,6 +592,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->recl = options.default_recl; u->recl = options.default_recl;
u->endfile = AT_ENDFILE; u->endfile = AT_ENDFILE;
......
...@@ -68,7 +68,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, ...@@ -68,7 +68,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
char *out; char *out;
char *digits; char *digits;
int e; int e;
char expchar; char expchar, rchar;
format_token ft; format_token ft;
int w; int w;
int d; int d;
...@@ -89,6 +89,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, ...@@ -89,6 +89,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
w = f->u.real.w; w = f->u.real.w;
d = f->u.real.d; d = f->u.real.d;
rchar = '5';
nzero_real = -1; nzero_real = -1;
/* We should always know the field width and precision. */ /* We should always know the field width and precision. */
...@@ -235,24 +236,75 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, ...@@ -235,24 +236,75 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
internal_error (&dtp->common, "Unexpected format token"); internal_error (&dtp->common, "Unexpected format token");
} }
/* Round the value. */ /* 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)
{
case ROUND_ZERO: /* Do nothing and truncation occurs. */
goto skip;
case ROUND_UP:
if (sign_bit)
goto skip;
rchar = '0';
break;
case ROUND_DOWN:
if (!sign_bit)
goto skip;
rchar = '0';
break;
case ROUND_NEAREST:
/* Round compatible unless there is a tie. A tie is a 5 with
all trailing zero's. */
i = nafter + 1;
if (digits[i] == '5')
{
for(i++ ; i < ndigits; i++)
{
if (digits[i] != '0')
goto do_rnd;
}
/* It is a tie so round to even. */
switch (digits[nafter])
{
case '1':
case '3':
case '5':
case '7':
case '9':
/* If odd, round away from zero to even. */
break;
default:
/* If even, skip rounding, truncate to even. */
goto skip;
}
}
/* Fall through. */
case ROUND_PROCDEFINED:
case ROUND_UNSPECIFIED:
case ROUND_COMPATIBLE:
rchar = '5';
/* Just fall through and do the actual rounding. */
}
do_rnd:
if (nbefore + nafter == 0) if (nbefore + nafter == 0)
{ {
ndigits = 0; ndigits = 0;
if (nzero_real == d && digits[0] >= '5') if (nzero_real == d && digits[0] >= rchar)
{ {
/* We rounded to zero but shouldn't have */ /* We rounded to zero but shouldn't have */
nzero--; nzero--;
nafter = 1; nafter = 1;
digits[0] = '1'; digits[0] = '1';
ndigits = 1; ndigits = 1;
} }
} }
else if (nbefore + nafter < ndigits) else if (nbefore + nafter < ndigits)
{ {
ndigits = nbefore + nafter; ndigits = nbefore + nafter;
i = ndigits; i = ndigits;
if (digits[i] >= '5') if (digits[i] >= rchar)
{ {
/* Propagate the carry. */ /* Propagate the carry. */
for (i--; i >= 0; i--) for (i--; i >= 0; i--)
...@@ -267,9 +319,10 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, ...@@ -267,9 +319,10 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
if (i < 0) if (i < 0)
{ {
/* The carry overflowed. Fortunately we have some spare space /* The carry overflowed. Fortunately we have some spare
at the start of the buffer. We may discard some digits, but space at the start of the buffer. We may discard some
this is ok because we already know they are zero. */ digits, but this is ok because we already know they are
zero. */
digits--; digits--;
digits[0] = '1'; digits[0] = '1';
if (ft == FMT_F) if (ft == FMT_F)
...@@ -297,6 +350,8 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, ...@@ -297,6 +350,8 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
} }
} }
skip:
/* Calculate the format of the exponent field. */ /* Calculate the format of the exponent field. */
if (expchar) if (expchar)
{ {
......
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