1 /* Copyright (C) 2007, 2008 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
3 Write float code factoring to this file by Jerry DeLisle
4 F2003 I/O support contributed by Jerry DeLisle
6 This file is part of the GNU Fortran 95 runtime library (libgfortran).
8 Libgfortran is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 In addition to the permissions in the GNU General Public License, the
14 Free Software Foundation gives you unlimited permission to link the
15 compiled version of this file into combinations with other programs,
16 and to distribute those combinations without any restriction coming
17 from the use of this file. (The General Public License restrictions
18 do apply in other respects; for example, they cover modification of
19 the file, and distribution when not linked into a combine
22 Libgfortran is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with Libgfortran; see the file COPYING. If not, write to
29 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
30 Boston, MA 02110-1301, USA. */
35 { S_NONE, S_MINUS, S_PLUS }
38 /* Given a flag that indicates if a value is negative or not, return a
39 sign_t that gives the sign that we need to produce. */
42 calculate_sign (st_parameter_dt *dtp, int negative_flag)
49 switch (dtp->u.p.sign_status)
51 case SIGN_SP: /* Show sign. */
54 case SIGN_SS: /* Suppress sign. */
57 case SIGN_S: /* Processor defined. */
58 s = options.optional_plus ? S_PLUS : S_NONE;
66 /* Output a real number according to its format which is FMT_G free. */
69 output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
70 int sign_bit, bool zero_flag, int ndigits, int edigits)
79 /* Number of digits before the decimal point. */
81 /* Number of zeros after the decimal point. */
83 /* Number of digits after the decimal point. */
85 /* Number of zeros after the decimal point, whatever the precision. */
98 /* We should always know the field width and precision. */
100 internal_error (&dtp->common, "Unspecified precision");
102 sign = calculate_sign (dtp, sign_bit);
104 /* The following code checks the given string has punctuation in the correct
105 places. Uncomment if needed for debugging.
106 if (d != 0 && ((buffer[2] != '.' && buffer[2] != ',')
107 || buffer[ndigits + 2] != 'e'))
108 internal_error (&dtp->common, "printf is broken"); */
110 /* Read the exponent back in. */
111 e = atoi (&buffer[ndigits + 3]) + 1;
113 /* Make sure zero comes out as 0.0e0. */
117 if (compile_options.sign_zero == 1)
118 sign = calculate_sign (dtp, sign_bit);
120 sign = calculate_sign (dtp, 0);
123 /* Normalize the fractional component. */
124 buffer[2] = buffer[1];
127 /* Figure out where to place the decimal point. */
131 nbefore = e + dtp->u.p.scale_factor;
151 i = dtp->u.p.scale_factor;
152 if (d <= 0 && i == 0)
154 generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
155 "greater than zero in format specifier 'E' or 'D'");
158 if (i <= -d || i >= d + 2)
160 generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
161 "out of range in format specifier 'E' or 'D'");
177 nafter = (d - i) + 1;
193 /* The exponent must be a multiple of three, with 1-3 digits before
194 the decimal point. */
203 nbefore = 3 - nbefore;
222 /* Should never happen. */
223 internal_error (&dtp->common, "Unexpected format token");
226 /* Round the value. */
227 if (nbefore + nafter == 0)
230 if (nzero_real == d && digits[0] >= '5')
232 /* We rounded to zero but shouldn't have */
239 else if (nbefore + nafter < ndigits)
241 ndigits = nbefore + nafter;
243 if (digits[i] >= '5')
245 /* Propagate the carry. */
246 for (i--; i >= 0; i--)
248 if (digits[i] != '9')
258 /* The carry overflowed. Fortunately we have some spare space
259 at the start of the buffer. We may discard some digits, but
260 this is ok because we already know they are zero. */
273 else if (ft == FMT_EN)
288 /* Calculate the format of the exponent field. */
292 for (i = abs (e); i >= 10; i /= 10)
297 /* Width not specified. Must be no more than 3 digits. */
298 if (e > 999 || e < -999)
303 if (e > 99 || e < -99)
309 /* Exponent width specified, check it is wide enough. */
310 if (edigits > f->u.real.e)
313 edigits = f->u.real.e + 2;
319 /* Pick a field size if none was specified. */
321 w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1);
323 /* Create the ouput buffer. */
324 out = write_block (dtp, w);
328 /* Zero values always output as positive, even if the value was negative
330 for (i = 0; i < ndigits; i++)
332 if (digits[i] != '0')
337 /* The output is zero, so set the sign according to the sign bit unless
338 -fno-sign-zero was specified. */
339 if (compile_options.sign_zero == 1)
340 sign = calculate_sign (dtp, sign_bit);
342 sign = calculate_sign (dtp, 0);
345 /* Work out how much padding is needed. */
346 nblanks = w - (nbefore + nzero + nafter + edigits + 1);
350 /* Check the value fits in the specified field width. */
351 if (nblanks < 0 || edigits == -1)
357 /* See if we have space for a zero before the decimal point. */
358 if (nbefore == 0 && nblanks > 0)
366 /* Pad to full field width. */
368 if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
370 memset (out, ' ', nblanks);
374 /* Output the initial sign (if any). */
377 else if (sign == S_MINUS)
380 /* Output an optional leading zero. */
384 /* Output the part before the decimal point, padding with zeros. */
387 if (nbefore > ndigits)
390 memcpy (out, digits, i);
398 memcpy (out, digits, i);
405 /* Output the decimal point. */
406 *(out++) = dtp->u.p.decimal_status == DECIMAL_POINT ? '.' : ',';
408 /* Output leading zeros after the decimal point. */
411 for (i = 0; i < nzero; i++)
415 /* Output digits after the decimal point, padding with zeros. */
418 if (nafter > ndigits)
423 memcpy (out, digits, i);
432 /* Output the exponent. */
441 snprintf (buffer, size, "%+0*d", edigits, e);
443 sprintf (buffer, "%+0*d", edigits, e);
445 memcpy (out, buffer, edigits);
447 if (dtp->u.p.no_leading_blank)
450 memset( out , ' ' , nblanks );
451 dtp->u.p.no_leading_blank = 0;
455 #undef MIN_FIELD_WIDTH
459 /* Write "Infinite" or "Nan" as appropriate for the given format. */
462 write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit)
467 if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
471 /* If the field width is zero, the processor must select a width
472 not zero. 4 is chosen to allow output of '-Inf' or '+Inf' */
475 p = write_block (dtp, nb);
490 /* If the sign is negative and the width is 3, there is
491 insufficient room to output '-Inf', so output asterisks */
499 /* The negative sign is mandatory */
505 /* The positive sign is optional, but we output it for
511 /* We have room, so output 'Infinity' */
512 memcpy(p + nb - 8, "Infinity", 8);
515 /* For the case of width equals 8, there is not enough room
516 for the sign and 'Infinity' so we go with 'Inf' */
517 memcpy(p + nb - 3, "Inf", 3);
519 if (nb < 9 && nb > 3)
520 p[nb - 4] = fin; /* Put the sign in front of Inf */
522 p[nb - 9] = fin; /* Put the sign in front of Infinity */
525 memcpy(p + nb - 3, "NaN", 3);
531 /* Returns the value of 10**d. */
533 #define CALCULATE_EXP(x) \
534 inline static GFC_REAL_ ## x \
535 calculate_exp_ ## x (int d)\
538 GFC_REAL_ ## x r = 1.0;\
539 for (i = 0; i< (d >= 0 ? d : -d); i++)\
541 r = (d >= 0) ? r : 1.0 / r;\
549 #ifdef HAVE_GFC_REAL_10
553 #ifdef HAVE_GFC_REAL_16
558 /* Generate corresponding I/O format for FMT_G and output.
559 The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
560 LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
562 Data Magnitude Equivalent Conversion
563 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
564 m = 0 F(w-n).(d-1), n' '
565 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
566 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
567 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
568 ................ ..........
569 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
570 m >= 10**d-0.5 Ew.d[Ee]
572 notes: for Gw.d , n' ' means 4 blanks
573 for Gw.dEe, n' ' means e+2 blanks */
575 #define OUTPUT_FLOAT_FMT_G(x) \
577 output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
578 GFC_REAL_ ## x m, char *buffer, size_t size, \
579 int sign_bit, bool zero_flag, int ndigits, int edigits) \
581 int e = f->u.real.e;\
582 int d = f->u.real.d;\
583 int w = f->u.real.w;\
585 GFC_REAL_ ## x exp_d;\
589 int save_scale_factor, nb = 0;\
591 save_scale_factor = dtp->u.p.scale_factor;\
592 newf = get_mem (sizeof (fnode));\
594 exp_d = calculate_exp_ ## x (d);\
595 if ((m > 0.0 && m < 0.1 - 0.05 / exp_d) || (m >= exp_d - 0.5 ) ||\
596 ((m == 0.0) && !(compile_options.allow_std & GFC_STD_F2003)))\
598 newf->format = FMT_E;\
614 GFC_REAL_ ## x temp;\
615 mid = (low + high) / 2;\
617 temp = 0.1 * calculate_exp_ ## x (mid) - 0.5\
618 * calculate_exp_ ## x (mid - d - 1);\
623 if (ubound == lbound + 1)\
630 if (ubound == lbound + 1)\
646 newf->format = FMT_F;\
647 newf->u.real.w = f->u.real.w - nb;\
650 newf->u.real.d = d - 1;\
652 newf->u.real.d = - (mid - d - 1);\
654 dtp->u.p.scale_factor = 0;\
657 output_float (dtp, newf, buffer, size, sign_bit, zero_flag, ndigits, \
659 dtp->u.p.scale_factor = save_scale_factor;\
665 p = write_block (dtp, nb);\
668 memset (p, ' ', nb);\
672 OUTPUT_FLOAT_FMT_G(4)
674 OUTPUT_FLOAT_FMT_G(8)
676 #ifdef HAVE_GFC_REAL_10
677 OUTPUT_FLOAT_FMT_G(10)
680 #ifdef HAVE_GFC_REAL_16
681 OUTPUT_FLOAT_FMT_G(16)
684 #undef OUTPUT_FLOAT_FMT_G
687 /* Define a macro to build code for write_float. */
689 /* Note: Before output_float is called, sprintf is used to print to buffer the
690 number in the format +D.DDDDe+ddd. For an N digit exponent, this gives us
691 (MIN_FIELD_WIDTH-5)-N digits after the decimal point, plus another one
692 before the decimal point.
694 # The result will always contain a decimal point, even if no
697 - The converted value is to be left adjusted on the field boundary
699 + A sign (+ or -) always be placed before a number
701 MIN_FIELD_WIDTH minimum field width
703 * (ndigits-1) is used as the precision
705 e format: [-]d.ddde±dd where there is one digit before the
706 decimal-point character and the number of digits after it is
707 equal to the precision. The exponent always contains at least two
708 digits; if the value is zero, the exponent is 00. */
713 snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
714 "e", ndigits - 1, tmp);
717 snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
718 "Le", ndigits - 1, tmp);
723 sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
724 "e", ndigits - 1, tmp);
727 sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
728 "Le", ndigits - 1, tmp);
732 #define WRITE_FLOAT(x,y)\
735 tmp = * (GFC_REAL_ ## x *)source;\
736 sign_bit = signbit (tmp);\
737 if (!isfinite (tmp))\
739 write_infnan (dtp, f, isnan (tmp), sign_bit);\
742 tmp = sign_bit ? -tmp : tmp;\
743 if (f->u.real.d == 0 && f->format == FMT_F)\
750 zero_flag = (tmp == 0.0);\
754 if (f->format != FMT_G)\
755 output_float (dtp, f, buffer, size, sign_bit, zero_flag, ndigits, \
758 output_float_FMT_G_ ## x (dtp, f, tmp, buffer, size, sign_bit, \
759 zero_flag, ndigits, edigits);\
762 /* Output a real number according to its format. */
765 write_float (st_parameter_dt *dtp, const fnode *f, const char *source, int len)
768 #if defined(HAVE_GFC_REAL_16) && __LDBL_DIG__ > 18
769 # define MIN_FIELD_WIDTH 46
771 # define MIN_FIELD_WIDTH 31
773 #define STR(x) STR1(x)
776 /* This must be large enough to accurately hold any value. */
777 char buffer[MIN_FIELD_WIDTH+1];
778 int sign_bit, ndigits, edigits;
782 size = MIN_FIELD_WIDTH+1;
784 /* printf pads blanks for us on the exponent so we just need it big enough
785 to handle the largest number of exponent digits expected. */
788 if (f->format == FMT_F || f->format == FMT_EN || f->format == FMT_G
789 || ((f->format == FMT_D || f->format == FMT_E)
790 && dtp->u.p.scale_factor != 0))
792 /* Always convert at full precision to avoid double rounding. */
793 ndigits = MIN_FIELD_WIDTH - 4 - edigits;
797 /* The number of digits is known, so let printf do the rounding. */
798 if (f->format == FMT_ES)
799 ndigits = f->u.real.d + 1;
801 ndigits = f->u.real.d;
802 if (ndigits > MIN_FIELD_WIDTH - 4 - edigits)
803 ndigits = MIN_FIELD_WIDTH - 4 - edigits;
816 #ifdef HAVE_GFC_REAL_10
821 #ifdef HAVE_GFC_REAL_16
827 internal_error (NULL, "bad real kind");