1 /* Copyright (C) 2007 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
3 Write float code factoring to this file by Jerry DeLisle
5 This file is part of the GNU Fortran 95 runtime library (libgfortran).
7 Libgfortran is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 In addition to the permissions in the GNU General Public License, the
13 Free Software Foundation gives you unlimited permission to link the
14 compiled version of this file into combinations with other programs,
15 and to distribute those combinations without any restriction coming
16 from the use of this file. (The General Public License restrictions
17 do apply in other respects; for example, they cover modification of
18 the file, and distribution when not linked into a combine
21 Libgfortran is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with Libgfortran; see the file COPYING. If not, write to
28 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
29 Boston, MA 02110-1301, USA. */
34 { SIGN_NONE, SIGN_MINUS, SIGN_PLUS }
37 /* Given a flag that indicates if a value is negative or not, return a
38 sign_t that gives the sign that we need to produce. */
41 calculate_sign (st_parameter_dt *dtp, int negative_flag)
48 switch (dtp->u.p.sign_status)
57 s = options.optional_plus ? SIGN_PLUS : SIGN_NONE;
65 /* Output a real number according to its format which is FMT_G free. */
68 output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
69 int sign_bit, bool zero_flag, int ndigits, int edigits)
78 /* Number of digits before the decimal point. */
80 /* Number of zeros after the decimal point. */
82 /* Number of digits after the decimal point. */
84 /* Number of zeros after the decimal point, whatever the precision. */
97 /* We should always know the field width and precision. */
99 internal_error (&dtp->common, "Unspecified precision");
101 /* Use sprintf to print the number in the format +D.DDDDe+ddd
102 For an N digit exponent, this gives us (MIN_FIELD_WIDTH-5)-N digits
103 after the decimal point, plus another one before the decimal point. */
105 sign = calculate_sign (dtp, sign_bit);
107 /* # The result will always contain a decimal point, even if no
110 * - The converted value is to be left adjusted on the field boundary
112 * + A sign (+ or -) always be placed before a number
114 * MIN_FIELD_WIDTH minimum field width
116 * * (ndigits-1) is used as the precision
118 * e format: [-]d.ddde±dd where there is one digit before the
119 * decimal-point character and the number of digits after it is
120 * equal to the precision. The exponent always contains at least two
121 * digits; if the value is zero, the exponent is 00.
124 /* Check the given string has punctuation in the correct places. */
125 if (d != 0 && (buffer[2] != '.' || buffer[ndigits + 2] != 'e'))
126 internal_error (&dtp->common, "printf is broken");
128 /* Read the exponent back in. */
129 e = atoi (&buffer[ndigits + 3]) + 1;
131 /* Make sure zero comes out as 0.0e0. */
135 if (compile_options.sign_zero == 1)
136 sign = calculate_sign (dtp, sign_bit);
138 sign = calculate_sign (dtp, 0);
141 /* Normalize the fractional component. */
142 buffer[2] = buffer[1];
145 /* Figure out where to place the decimal point. */
149 nbefore = e + dtp->u.p.scale_factor;
169 i = dtp->u.p.scale_factor;
170 if (d <= 0 && i == 0)
172 generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
173 "greater than zero in format specifier 'E' or 'D'");
176 if (i <= -d || i >= d + 2)
178 generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
179 "out of range in format specifier 'E' or 'D'");
195 nafter = (d - i) + 1;
211 /* The exponent must be a multiple of three, with 1-3 digits before
212 the decimal point. */
221 nbefore = 3 - nbefore;
240 /* Should never happen. */
241 internal_error (&dtp->common, "Unexpected format token");
244 /* Round the value. */
245 if (nbefore + nafter == 0)
248 if (nzero_real == d && digits[0] >= '5')
250 /* We rounded to zero but shouldn't have */
257 else if (nbefore + nafter < ndigits)
259 ndigits = nbefore + nafter;
261 if (digits[i] >= '5')
263 /* Propagate the carry. */
264 for (i--; i >= 0; i--)
266 if (digits[i] != '9')
276 /* The carry overflowed. Fortunately we have some spare space
277 at the start of the buffer. We may discard some digits, but
278 this is ok because we already know they are zero. */
291 else if (ft == FMT_EN)
306 /* Calculate the format of the exponent field. */
310 for (i = abs (e); i >= 10; i /= 10)
315 /* Width not specified. Must be no more than 3 digits. */
316 if (e > 999 || e < -999)
321 if (e > 99 || e < -99)
327 /* Exponent width specified, check it is wide enough. */
328 if (edigits > f->u.real.e)
331 edigits = f->u.real.e + 2;
337 /* Pick a field size if none was specified. */
339 w = nbefore + nzero + nafter + (sign != SIGN_NONE ? 2 : 1);
341 /* Create the ouput buffer. */
342 out = write_block (dtp, w);
346 /* Zero values always output as positive, even if the value was negative
348 for (i = 0; i < ndigits; i++)
350 if (digits[i] != '0')
355 /* The output is zero, so set the sign according to the sign bit unless
356 -fno-sign-zero was specified. */
357 if (compile_options.sign_zero == 1)
358 sign = calculate_sign (dtp, sign_bit);
360 sign = calculate_sign (dtp, 0);
363 /* Work out how much padding is needed. */
364 nblanks = w - (nbefore + nzero + nafter + edigits + 1);
365 if (sign != SIGN_NONE)
368 /* Check the value fits in the specified field width. */
369 if (nblanks < 0 || edigits == -1)
375 /* See if we have space for a zero before the decimal point. */
376 if (nbefore == 0 && nblanks > 0)
384 /* Pad to full field width. */
386 if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
388 memset (out, ' ', nblanks);
392 /* Output the initial sign (if any). */
393 if (sign == SIGN_PLUS)
395 else if (sign == SIGN_MINUS)
398 /* Output an optional leading zero. */
402 /* Output the part before the decimal point, padding with zeros. */
405 if (nbefore > ndigits)
408 memcpy (out, digits, i);
416 memcpy (out, digits, i);
423 /* Output the decimal point. */
426 /* Output leading zeros after the decimal point. */
429 for (i = 0; i < nzero; i++)
433 /* Output digits after the decimal point, padding with zeros. */
436 if (nafter > ndigits)
441 memcpy (out, digits, i);
450 /* Output the exponent. */
459 snprintf (buffer, size, "%+0*d", edigits, e);
461 sprintf (buffer, "%+0*d", edigits, e);
463 memcpy (out, buffer, edigits);
465 if (dtp->u.p.no_leading_blank)
468 memset( out , ' ' , nblanks );
469 dtp->u.p.no_leading_blank = 0;
473 #undef MIN_FIELD_WIDTH
477 /* Write "Infinite" or "Nan" as appropriate for the given format. */
480 write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit)
485 if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
489 /* If the field width is zero, the processor must select a width
490 not zero. 4 is chosen to allow output of '-Inf' or '+Inf' */
493 p = write_block (dtp, nb);
508 /* If the sign is negative and the width is 3, there is
509 insufficient room to output '-Inf', so output asterisks */
517 /* The negative sign is mandatory */
523 /* The positive sign is optional, but we output it for
529 /* We have room, so output 'Infinity' */
530 memcpy(p + nb - 8, "Infinity", 8);
533 /* For the case of width equals 8, there is not enough room
534 for the sign and 'Infinity' so we go with 'Inf' */
535 memcpy(p + nb - 3, "Inf", 3);
537 if (nb < 9 && nb > 3)
538 p[nb - 4] = fin; /* Put the sign in front of Inf */
540 p[nb - 9] = fin; /* Put the sign in front of Infinity */
543 memcpy(p + nb - 3, "NaN", 3);
549 /* Returns the value of 10**d. */
551 #define CALCULATE_EXP(x) \
552 inline static GFC_REAL_ ## x \
553 calculate_exp_ ## x (int d)\
556 GFC_REAL_ ## x r = 1.0;\
557 for (i = 0; i< (d >= 0 ? d : -d); i++)\
559 r = (d >= 0) ? r : 1.0 / r;\
567 #ifdef HAVE_GFC_REAL_10
571 #ifdef HAVE_GFC_REAL_16
576 /* Generate corresponding I/O format for FMT_G and output.
577 The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
578 LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
580 Data Magnitude Equivalent Conversion
581 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
582 m = 0 F(w-n).(d-1), n' '
583 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
584 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
585 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
586 ................ ..........
587 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
588 m >= 10**d-0.5 Ew.d[Ee]
590 notes: for Gw.d , n' ' means 4 blanks
591 for Gw.dEe, n' ' means e+2 blanks */
593 #define OUTPUT_FLOAT_FMT_G(x) \
595 output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
596 GFC_REAL_ ## x m, char *buffer, size_t size, \
597 int sign_bit, bool zero_flag, int ndigits, int edigits) \
599 int e = f->u.real.e;\
600 int d = f->u.real.d;\
601 int w = f->u.real.w;\
603 GFC_REAL_ ## x exp_d;\
607 int save_scale_factor, nb = 0;\
609 save_scale_factor = dtp->u.p.scale_factor;\
610 newf = get_mem (sizeof (fnode));\
612 exp_d = calculate_exp_ ## x (d);\
613 if ((m > 0.0 && m < 0.1 - 0.05 / exp_d) || (m >= exp_d - 0.5 ) ||\
614 ((m == 0.0) && !(compile_options.allow_std & GFC_STD_F2003)))\
616 newf->format = FMT_E;\
632 GFC_REAL_ ## x temp;\
633 mid = (low + high) / 2;\
635 temp = 0.1 * calculate_exp_ ## x (mid) - 0.5\
636 * calculate_exp_ ## x (mid - d - 1);\
641 if (ubound == lbound + 1)\
648 if (ubound == lbound + 1)\
664 newf->format = FMT_F;\
665 newf->u.real.w = f->u.real.w - nb;\
668 newf->u.real.d = d - 1;\
670 newf->u.real.d = - (mid - d - 1);\
672 dtp->u.p.scale_factor = 0;\
675 output_float (dtp, newf, buffer, size, sign_bit, zero_flag, ndigits, \
677 dtp->u.p.scale_factor = save_scale_factor;\
683 p = write_block (dtp, nb);\
686 memset (p, ' ', nb);\
690 OUTPUT_FLOAT_FMT_G(4)
692 OUTPUT_FLOAT_FMT_G(8)
694 #ifdef HAVE_GFC_REAL_10
695 OUTPUT_FLOAT_FMT_G(10)
698 #ifdef HAVE_GFC_REAL_16
699 OUTPUT_FLOAT_FMT_G(16)
702 #undef OUTPUT_FLOAT_FMT_G
704 /* Define a macro to build code for write_float. */
709 snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
710 "e", ndigits - 1, tmp);
713 snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
714 "Le", ndigits - 1, tmp);
719 sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
720 "e", ndigits - 1, tmp);
723 sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
724 "Le", ndigits - 1, tmp);
728 #define WRITE_FLOAT(x,y)\
731 tmp = * (GFC_REAL_ ## x *)source;\
732 sign_bit = signbit (tmp);\
733 if (!isfinite (tmp))\
735 write_infnan (dtp, f, isnan (tmp), sign_bit);\
738 tmp = sign_bit ? -tmp : tmp;\
739 if (f->u.real.d == 0 && f->format == FMT_F)\
746 zero_flag = (tmp == 0.0);\
750 if (f->format != FMT_G)\
751 output_float (dtp, f, buffer, size, sign_bit, zero_flag, ndigits, \
754 output_float_FMT_G_ ## x (dtp, f, tmp, buffer, size, sign_bit, \
755 zero_flag, ndigits, edigits);\
758 /* Output a real number according to its format. */
761 write_float (st_parameter_dt *dtp, const fnode *f, const char *source, int len)
764 #if defined(HAVE_GFC_REAL_16) && __LDBL_DIG__ > 18
765 # define MIN_FIELD_WIDTH 46
767 # define MIN_FIELD_WIDTH 31
769 #define STR(x) STR1(x)
772 /* This must be large enough to accurately hold any value. */
773 char buffer[MIN_FIELD_WIDTH+1];
774 int sign_bit, ndigits, edigits;
778 size = MIN_FIELD_WIDTH+1;
780 /* printf pads blanks for us on the exponent so we just need it big enough
781 to handle the largest number of exponent digits expected. */
784 if (f->format == FMT_F || f->format == FMT_EN || f->format == FMT_G
785 || ((f->format == FMT_D || f->format == FMT_E)
786 && dtp->u.p.scale_factor != 0))
788 /* Always convert at full precision to avoid double rounding. */
789 ndigits = MIN_FIELD_WIDTH - 4 - edigits;
793 /* The number of digits is known, so let printf do the rounding. */
794 if (f->format == FMT_ES)
795 ndigits = f->u.real.d + 1;
797 ndigits = f->u.real.d;
798 if (ndigits > MIN_FIELD_WIDTH - 4 - edigits)
799 ndigits = MIN_FIELD_WIDTH - 4 - edigits;
812 #ifdef HAVE_GFC_REAL_10
817 #ifdef HAVE_GFC_REAL_16
823 internal_error (NULL, "bad real kind");