X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=libgfortran%2Fio%2Fwrite_float.def;h=45c2a17a50d805e7f9c7e45d2aab6d7f8e5ba1b5;hp=028fd27b863bb393ef1f46fc5231996f6d04d978;hb=09c759aaf6da911aa1a44898d2b84121991bced9;hpb=e902a4d4b05798748e92cd868a1d7a92346b5a41 diff --git a/libgfortran/io/write_float.def b/libgfortran/io/write_float.def index 028fd27b863..45c2a17a50d 100644 --- a/libgfortran/io/write_float.def +++ b/libgfortran/io/write_float.def @@ -1,37 +1,33 @@ -/* Copyright (C) 2007 Free Software Foundation, Inc. +/* Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Andy Vaught Write float code factoring to this file by Jerry DeLisle + F2003 I/O support contributed by Jerry DeLisle -This file is part of the GNU Fortran 95 runtime library (libgfortran). +This file is part of the GNU Fortran runtime library (libgfortran). Libgfortran is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) +the Free Software Foundation; either version 3, or (at your option) any later version. -In addition to the permissions in the GNU General Public License, the -Free Software Foundation gives you unlimited permission to link the -compiled version of this file into combinations with other programs, -and to distribute those combinations without any restriction coming -from the use of this file. (The General Public License restrictions -do apply in other respects; for example, they cover modification of -the file, and distribution when not linked into a combine -executable.) - Libgfortran is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with Libgfortran; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ #include "config.h" typedef enum -{ SIGN_NONE, SIGN_MINUS, SIGN_PLUS } +{ S_NONE, S_MINUS, S_PLUS } sign_t; /* Given a flag that indicates if a value is negative or not, return a @@ -40,21 +36,22 @@ sign_t; static sign_t calculate_sign (st_parameter_dt *dtp, int negative_flag) { - sign_t s = SIGN_NONE; + sign_t s = S_NONE; if (negative_flag) - s = SIGN_MINUS; + s = S_MINUS; else switch (dtp->u.p.sign_status) { - case SIGN_SP: - s = SIGN_PLUS; + case SIGN_SP: /* Show sign. */ + s = S_PLUS; break; - case SIGN_SS: - s = SIGN_NONE; + case SIGN_SS: /* Suppress sign. */ + s = S_NONE; break; - case SIGN_S: - s = options.optional_plus ? SIGN_PLUS : SIGN_NONE; + case SIGN_S: /* Processor defined. */ + case SIGN_UNSPECIFIED: + s = options.optional_plus ? S_PLUS : S_NONE; break; } @@ -71,7 +68,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, char *out; char *digits; int e; - char expchar; + char expchar, rchar; format_token ft; int w; int d; @@ -92,38 +89,20 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, w = f->u.real.w; d = f->u.real.d; + rchar = '5'; nzero_real = -1; /* We should always know the field width and precision. */ if (d < 0) internal_error (&dtp->common, "Unspecified precision"); - /* Use sprintf to print the 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 before the decimal point. */ - sign = calculate_sign (dtp, sign_bit); - - /* # 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 - * - * MIN_FIELD_WIDTH minimum field width - * - * * (ndigits-1) 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. - */ - - /* Check the given string has punctuation in the correct places. */ - if (d != 0 && (buffer[2] != '.' || buffer[ndigits + 2] != 'e')) - internal_error (&dtp->common, "printf is broken"); + + /* The following code checks the given string has punctuation in the correct + places. Uncomment if needed for debugging. + if (d != 0 && ((buffer[2] != '.' && buffer[2] != ',') + || buffer[ndigits + 2] != 'e')) + internal_error (&dtp->common, "printf is broken"); */ /* Read the exponent back in. */ e = atoi (&buffer[ndigits + 3]) + 1; @@ -136,6 +115,22 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, sign = calculate_sign (dtp, sign_bit); else sign = calculate_sign (dtp, 0); + + /* Handle special cases. */ + if (w == 0) + w = d + 2; + + /* For this one we choose to not output a decimal point. + F95 10.5.1.2.1 */ + if (w == 1 && ft == FMT_F) + { + out = write_block (dtp, w); + if (out == NULL) + return; + *out = '0'; + return; + } + } /* Normalize the fractional component. */ @@ -146,6 +141,13 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, switch (ft) { case FMT_F: + if (d == 0 && e <= 0 && dtp->u.p.scale_factor == 0) + { + memmove (digits + 1, digits, ndigits - 1); + digits[0] = '0'; + e++; + } + nbefore = e + dtp->u.p.scale_factor; if (nbefore < 0) { @@ -241,24 +243,75 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, 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 + nbefore; + 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 + nbefore - 1]) + { + 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) { ndigits = 0; - if (nzero_real == d && digits[0] >= '5') - { - /* We rounded to zero but shouldn't have */ - nzero--; - nafter = 1; - digits[0] = '1'; - ndigits = 1; - } + if (nzero_real == d && digits[0] >= rchar) + { + /* We rounded to zero but shouldn't have */ + nzero--; + nafter = 1; + digits[0] = '1'; + ndigits = 1; + } } else if (nbefore + nafter < ndigits) { ndigits = nbefore + nafter; i = ndigits; - if (digits[i] >= '5') + if (digits[i] >= rchar) { /* Propagate the carry. */ for (i--; i >= 0; i--) @@ -273,9 +326,10 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, if (i < 0) { - /* The carry overflowed. Fortunately we have some spare space - at the start of the buffer. We may discard some digits, but - this is ok because we already know they are zero. */ + /* The carry overflowed. Fortunately we have some spare + space at the start of the buffer. We may discard some + digits, but this is ok because we already know they are + zero. */ digits--; digits[0] = '1'; if (ft == FMT_F) @@ -303,6 +357,8 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, } } + skip: + /* Calculate the format of the exponent field. */ if (expchar) { @@ -334,15 +390,6 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, else edigits = 0; - /* Pick a field size if none was specified. */ - if (w <= 0) - w = nbefore + nzero + nafter + (sign != SIGN_NONE ? 2 : 1); - - /* Create the ouput buffer. */ - out = write_block (dtp, w); - if (out == NULL) - return; - /* Zero values always output as positive, even if the value was negative before rounding. */ for (i = 0; i < ndigits; i++) @@ -360,11 +407,26 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, sign = calculate_sign (dtp, 0); } + /* Pick a field size if none was specified. */ + if (w <= 0) + w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1); + /* Work out how much padding is needed. */ nblanks = w - (nbefore + nzero + nafter + edigits + 1); - if (sign != SIGN_NONE) + if (sign != S_NONE) nblanks--; + if (dtp->u.p.g0_no_blanks) + { + w -= nblanks; + nblanks = 0; + } + + /* Create the ouput buffer. */ + out = write_block (dtp, w); + if (out == NULL) + return; + /* Check the value fits in the specified field width. */ if (nblanks < 0 || edigits == -1) { @@ -390,9 +452,9 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, } /* Output the initial sign (if any). */ - if (sign == SIGN_PLUS) + if (sign == S_PLUS) *(out++) = '+'; - else if (sign == SIGN_MINUS) + else if (sign == S_MINUS) *(out++) = '-'; /* Output an optional leading zero. */ @@ -420,8 +482,9 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, digits += i; out += nbefore; } + /* Output the decimal point. */ - *(out++) = '.'; + *(out++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ','; /* Output leading zeros after the decimal point. */ if (nzero > 0) @@ -462,12 +525,14 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, #endif memcpy (out, buffer, edigits); } + if (dtp->u.p.no_leading_blank) { out += edigits; memset( out , ' ' , nblanks ); dtp->u.p.no_leading_blank = 0; } + #undef STR #undef STR1 #undef MIN_FIELD_WIDTH @@ -600,17 +665,17 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \ int d = f->u.real.d;\ int w = f->u.real.w;\ fnode *newf;\ - GFC_REAL_ ## x exp_d;\ + GFC_REAL_ ## x rexp_d;\ int low, high, mid;\ int ubound, lbound;\ char *p;\ int save_scale_factor, nb = 0;\ \ save_scale_factor = dtp->u.p.scale_factor;\ - newf = get_mem (sizeof (fnode));\ + newf = (fnode *) get_mem (sizeof (fnode));\ \ - exp_d = calculate_exp_ ## x (d);\ - if ((m > 0.0 && m < 0.1 - 0.05 / exp_d) || (m >= exp_d - 0.5 ) ||\ + rexp_d = calculate_exp_ ## x (-d);\ + if ((m > 0.0 && m < 0.1 - 0.05 * rexp_d) || (rexp_d * (m + 0.5) >= 1.0) ||\ ((m == 0.0) && !(compile_options.allow_std & GFC_STD_F2003)))\ { \ newf->format = FMT_E;\ @@ -632,8 +697,7 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \ GFC_REAL_ ## x temp;\ mid = (low + high) / 2;\ \ - temp = 0.1 * calculate_exp_ ## x (mid) - 0.5\ - * calculate_exp_ ## x (mid - d - 1);\ + temp = (calculate_exp_ ## x (mid - 1) * (1 - 0.5 * rexp_d));\ \ if (m < temp)\ { \ @@ -653,7 +717,10 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \ low = mid + 1;\ }\ else\ - break;\ + {\ + mid++;\ + break;\ + }\ }\ \ if (e < 0)\ @@ -676,9 +743,9 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \ edigits);\ dtp->u.p.scale_factor = save_scale_factor;\ \ - free_mem(newf);\ + free (newf);\ \ - if (nb > 0)\ + if (nb > 0 && !dtp->u.p.g0_no_blanks)\ { \ p = write_block (dtp, nb);\ if (p == NULL)\ @@ -701,8 +768,30 @@ OUTPUT_FLOAT_FMT_G(16) #undef OUTPUT_FLOAT_FMT_G + /* Define a macro to build code for write_float. */ + /* Note: Before output_float is called, sprintf is used to print to buffer the + 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 + before the decimal point. + + # 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 + + MIN_FIELD_WIDTH minimum field width + + * (ndigits-1) 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. */ + #ifdef HAVE_SNPRINTF #define DTOA \ @@ -729,20 +818,13 @@ sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \ {\ GFC_REAL_ ## x tmp;\ tmp = * (GFC_REAL_ ## x *)source;\ - sign_bit = signbit (tmp);\ + sign_bit = __builtin_signbit (tmp);\ if (!isfinite (tmp))\ { \ write_infnan (dtp, f, isnan (tmp), sign_bit);\ return;\ }\ tmp = sign_bit ? -tmp : tmp;\ - if (f->u.real.d == 0 && f->format == FMT_F)\ - {\ - if (tmp < 0.5)\ - tmp = 0.0;\ - else if (tmp < 1.0)\ - tmp = tmp + 0.5;\ - }\ zero_flag = (tmp == 0.0);\ \ DTOA ## y\