2018-03-08 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libgfortran / io / write_float.def
blob177a568e041d66bf1e302170a16b3d65da6611e6
1 /* Copyright (C) 2007-2018 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 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 3, or (at your option)
11 any later version.
13 Libgfortran is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
27 #include "config.h"
29 typedef enum
30 { S_NONE, S_MINUS, S_PLUS }
31 sign_t;
33 /* Given a flag that indicates if a value is negative or not, return a
34 sign_t that gives the sign that we need to produce. */
36 static sign_t
37 calculate_sign (st_parameter_dt *dtp, int negative_flag)
39 sign_t s = S_NONE;
41 if (negative_flag)
42 s = S_MINUS;
43 else
44 switch (dtp->u.p.sign_status)
46 case SIGN_SP: /* Show sign. */
47 s = S_PLUS;
48 break;
49 case SIGN_SS: /* Suppress sign. */
50 s = S_NONE;
51 break;
52 case SIGN_S: /* Processor defined. */
53 case SIGN_UNSPECIFIED:
54 s = options.optional_plus ? S_PLUS : S_NONE;
55 break;
58 return s;
62 /* Determine the precision except for EN format. For G format,
63 determines an upper bound to be used for sizing the buffer. */
65 static int
66 determine_precision (st_parameter_dt * dtp, const fnode * f, int len)
68 int precision = f->u.real.d;
70 switch (f->format)
72 case FMT_F:
73 case FMT_G:
74 precision += dtp->u.p.scale_factor;
75 break;
76 case FMT_ES:
77 /* Scale factor has no effect on output. */
78 break;
79 case FMT_E:
80 case FMT_D:
81 /* See F2008 10.7.2.3.3.6 */
82 if (dtp->u.p.scale_factor <= 0)
83 precision += dtp->u.p.scale_factor - 1;
84 break;
85 default:
86 return -1;
89 /* If the scale factor has a large negative value, we must do our
90 own rounding? Use ROUND='NEAREST', which should be what snprintf
91 is using as well. */
92 if (precision < 0 &&
93 (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
94 || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
95 dtp->u.p.current_unit->round_status = ROUND_NEAREST;
97 /* Add extra guard digits up to at least full precision when we do
98 our own rounding. */
99 if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
100 && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
102 precision += 2 * len + 4;
103 if (precision < 0)
104 precision = 0;
107 return precision;
111 /* Build a real number according to its format which is FMT_G free. */
113 static void
114 build_float_string (st_parameter_dt *dtp, const fnode *f, char *buffer,
115 size_t size, int nprinted, int precision, int sign_bit,
116 bool zero_flag, int npad, char *result, size_t *len)
118 char *put;
119 char *digits;
120 int e, w, d, p, i;
121 char expchar, rchar;
122 format_token ft;
123 /* Number of digits before the decimal point. */
124 int nbefore;
125 /* Number of zeros after the decimal point. */
126 int nzero;
127 /* Number of digits after the decimal point. */
128 int nafter;
129 int leadzero;
130 int nblanks;
131 int ndigits, edigits;
132 sign_t sign;
134 ft = f->format;
135 w = f->u.real.w;
136 d = f->u.real.d;
137 p = dtp->u.p.scale_factor;
139 rchar = '5';
141 /* We should always know the field width and precision. */
142 if (d < 0)
143 internal_error (&dtp->common, "Unspecified precision");
145 sign = calculate_sign (dtp, sign_bit);
147 /* Calculate total number of digits. */
148 if (ft == FMT_F)
149 ndigits = nprinted - 2;
150 else
151 ndigits = precision + 1;
153 /* Read the exponent back in. */
154 if (ft != FMT_F)
155 e = atoi (&buffer[ndigits + 3]) + 1;
156 else
157 e = 0;
159 /* Make sure zero comes out as 0.0e0. */
160 if (zero_flag)
161 e = 0;
163 /* Normalize the fractional component. */
164 if (ft != FMT_F)
166 buffer[2] = buffer[1];
167 digits = &buffer[2];
169 else
170 digits = &buffer[1];
172 /* Figure out where to place the decimal point. */
173 switch (ft)
175 case FMT_F:
176 nbefore = ndigits - precision;
177 if ((w > 0) && (nbefore > (int) size))
179 *len = w;
180 star_fill (result, w);
181 result[w] = '\0';
182 return;
184 /* Make sure the decimal point is a '.'; depending on the
185 locale, this might not be the case otherwise. */
186 digits[nbefore] = '.';
187 if (p != 0)
189 if (p > 0)
191 memmove (digits + nbefore, digits + nbefore + 1, p);
192 digits[nbefore + p] = '.';
193 nbefore += p;
194 nafter = d;
195 nzero = 0;
197 else /* p < 0 */
199 if (nbefore + p >= 0)
201 nzero = 0;
202 memmove (digits + nbefore + p + 1, digits + nbefore + p, -p);
203 nbefore += p;
204 digits[nbefore] = '.';
205 nafter = d;
207 else
209 nzero = -(nbefore + p);
210 memmove (digits + 1, digits, nbefore);
211 nafter = d - nzero;
212 if (nafter == 0 && d > 0)
214 /* This is needed to get the correct rounding. */
215 memmove (digits + 1, digits, ndigits - 1);
216 digits[1] = '0';
217 nafter = 1;
218 nzero = d - 1;
220 else if (nafter < 0)
222 /* Reset digits to 0 in order to get correct rounding
223 towards infinity. */
224 for (i = 0; i < ndigits; i++)
225 digits[i] = '0';
226 digits[ndigits - 1] = '1';
227 nafter = d;
228 nzero = 0;
230 nbefore = 0;
234 else
236 nzero = 0;
237 nafter = d;
240 while (digits[0] == '0' && nbefore > 0)
242 digits++;
243 nbefore--;
244 ndigits--;
247 expchar = 0;
248 /* If we need to do rounding ourselves, get rid of the dot by
249 moving the fractional part. */
250 if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
251 && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
252 memmove (digits + nbefore, digits + nbefore + 1, ndigits - nbefore);
253 break;
255 case FMT_E:
256 case FMT_D:
257 i = dtp->u.p.scale_factor;
258 if (d <= 0 && p == 0)
260 generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
261 "greater than zero in format specifier 'E' or 'D'");
262 return;
264 if (p <= -d || p >= d + 2)
266 generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
267 "out of range in format specifier 'E' or 'D'");
268 return;
271 if (!zero_flag)
272 e -= p;
273 if (p < 0)
275 nbefore = 0;
276 nzero = -p;
277 nafter = d + p;
279 else if (p > 0)
281 nbefore = p;
282 nzero = 0;
283 nafter = (d - p) + 1;
285 else /* p == 0 */
287 nbefore = 0;
288 nzero = 0;
289 nafter = d;
292 if (ft == FMT_E)
293 expchar = 'E';
294 else
295 expchar = 'D';
296 break;
298 case FMT_EN:
299 /* The exponent must be a multiple of three, with 1-3 digits before
300 the decimal point. */
301 if (!zero_flag)
302 e--;
303 if (e >= 0)
304 nbefore = e % 3;
305 else
307 nbefore = (-e) % 3;
308 if (nbefore != 0)
309 nbefore = 3 - nbefore;
311 e -= nbefore;
312 nbefore++;
313 nzero = 0;
314 nafter = d;
315 expchar = 'E';
316 break;
318 case FMT_ES:
319 if (!zero_flag)
320 e--;
321 nbefore = 1;
322 nzero = 0;
323 nafter = d;
324 expchar = 'E';
325 break;
327 default:
328 /* Should never happen. */
329 internal_error (&dtp->common, "Unexpected format token");
332 if (zero_flag)
333 goto skip;
335 /* Round the value. The value being rounded is an unsigned magnitude. */
336 switch (dtp->u.p.current_unit->round_status)
338 /* For processor defined and unspecified rounding we use
339 snprintf to print the exact number of digits needed, and thus
340 let snprintf handle the rounding. On system claiming support
341 for IEEE 754, this ought to be round to nearest, ties to
342 even, corresponding to the Fortran ROUND='NEAREST'. */
343 case ROUND_PROCDEFINED:
344 case ROUND_UNSPECIFIED:
345 case ROUND_ZERO: /* Do nothing and truncation occurs. */
346 goto skip;
347 case ROUND_UP:
348 if (sign_bit)
349 goto skip;
350 goto updown;
351 case ROUND_DOWN:
352 if (!sign_bit)
353 goto skip;
354 goto updown;
355 case ROUND_NEAREST:
356 /* Round compatible unless there is a tie. A tie is a 5 with
357 all trailing zero's. */
358 i = nafter + nbefore;
359 if (digits[i] == '5')
361 for(i++ ; i < ndigits; i++)
363 if (digits[i] != '0')
364 goto do_rnd;
366 /* It is a tie so round to even. */
367 switch (digits[nafter + nbefore - 1])
369 case '1':
370 case '3':
371 case '5':
372 case '7':
373 case '9':
374 /* If odd, round away from zero to even. */
375 break;
376 default:
377 /* If even, skip rounding, truncate to even. */
378 goto skip;
381 /* Fall through. */
382 /* The ROUND_COMPATIBLE is rounding away from zero when there is a tie. */
383 case ROUND_COMPATIBLE:
384 rchar = '5';
385 goto do_rnd;
388 updown:
390 rchar = '0';
391 if (ft != FMT_F && w > 0 && d == 0 && p == 0)
392 nbefore = 1;
393 /* Scan for trailing zeros to see if we really need to round it. */
394 for(i = nbefore + nafter; i < ndigits; i++)
396 if (digits[i] != '0')
397 goto do_rnd;
399 goto skip;
401 do_rnd:
403 if (nbefore + nafter == 0)
404 /* Handle the case Fw.0 and value < 1.0 */
406 ndigits = 0;
407 if (digits[0] >= rchar)
409 /* We rounded to zero but shouldn't have */
410 nbefore = 1;
411 digits--;
412 digits[0] = '1';
413 ndigits = 1;
416 else if (nbefore + nafter < ndigits)
418 i = ndigits = nbefore + nafter;
419 if (digits[i] >= rchar)
421 /* Propagate the carry. */
422 for (i--; i >= 0; i--)
424 if (digits[i] != '9')
426 digits[i]++;
427 break;
429 digits[i] = '0';
432 if (i < 0)
434 /* The carry overflowed. Fortunately we have some spare
435 space at the start of the buffer. We may discard some
436 digits, but this is ok because we already know they are
437 zero. */
438 digits--;
439 digits[0] = '1';
440 if (ft == FMT_F)
442 if (nzero > 0)
444 nzero--;
445 nafter++;
447 else
448 nbefore++;
450 else if (ft == FMT_EN)
452 nbefore++;
453 if (nbefore == 4)
455 nbefore = 1;
456 e += 3;
459 else
460 e++;
465 skip:
467 /* Calculate the format of the exponent field. */
468 if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
470 edigits = 1;
471 for (i = abs (e); i >= 10; i /= 10)
472 edigits++;
474 if (f->u.real.e < 0)
476 /* Width not specified. Must be no more than 3 digits. */
477 if (e > 999 || e < -999)
478 edigits = -1;
479 else
481 edigits = 4;
482 if (e > 99 || e < -99)
483 expchar = ' ';
486 else
488 /* Exponent width specified, check it is wide enough. */
489 if (edigits > f->u.real.e)
490 edigits = -1;
491 else
492 edigits = f->u.real.e + 2;
495 else
496 edigits = 0;
498 /* Scan the digits string and count the number of zeros. If we make it
499 all the way through the loop, we know the value is zero after the
500 rounding completed above. */
501 int hasdot = 0;
502 for (i = 0; i < ndigits + hasdot; i++)
504 if (digits[i] == '.')
505 hasdot = 1;
506 else if (digits[i] != '0')
507 break;
510 /* To format properly, we need to know if the rounded result is zero and if
511 so, we set the zero_flag which may have been already set for
512 actual zero. */
513 if (i == ndigits + hasdot)
515 zero_flag = true;
516 /* The output is zero, so set the sign according to the sign bit unless
517 -fno-sign-zero was specified. */
518 if (compile_options.sign_zero == 1)
519 sign = calculate_sign (dtp, sign_bit);
520 else
521 sign = calculate_sign (dtp, 0);
524 /* Pick a field size if none was specified, taking into account small
525 values that may have been rounded to zero. */
526 if (w <= 0)
528 if (zero_flag)
529 w = d + (sign != S_NONE ? 2 : 1) + (d == 0 ? 1 : 0);
530 else
532 w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1);
533 w = w == 1 ? 2 : w;
537 /* Work out how much padding is needed. */
538 nblanks = w - (nbefore + nzero + nafter + edigits + 1);
539 if (sign != S_NONE)
540 nblanks--;
542 /* See if we have space for a zero before the decimal point. */
543 if (nbefore == 0 && nblanks > 0)
545 leadzero = 1;
546 nblanks--;
548 else
549 leadzero = 0;
551 if (dtp->u.p.g0_no_blanks)
553 w -= nblanks;
554 nblanks = 0;
557 /* Create the final float string. */
558 *len = w + npad;
559 put = result;
561 /* Check the value fits in the specified field width. */
562 if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE))
564 star_fill (put, *len);
565 return;
568 /* Pad to full field width. */
569 if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
571 memset (put, ' ', nblanks);
572 put += nblanks;
575 /* Set the initial sign (if any). */
576 if (sign == S_PLUS)
577 *(put++) = '+';
578 else if (sign == S_MINUS)
579 *(put++) = '-';
581 /* Set an optional leading zero. */
582 if (leadzero)
583 *(put++) = '0';
585 /* Set the part before the decimal point, padding with zeros. */
586 if (nbefore > 0)
588 if (nbefore > ndigits)
590 i = ndigits;
591 memcpy (put, digits, i);
592 ndigits = 0;
593 while (i < nbefore)
594 put[i++] = '0';
596 else
598 i = nbefore;
599 memcpy (put, digits, i);
600 ndigits -= i;
603 digits += i;
604 put += nbefore;
607 /* Set the decimal point. */
608 *(put++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
609 if (ft == FMT_F
610 && (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
611 || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
612 digits++;
614 /* Set leading zeros after the decimal point. */
615 if (nzero > 0)
617 for (i = 0; i < nzero; i++)
618 *(put++) = '0';
621 /* Set digits after the decimal point, padding with zeros. */
622 if (nafter > 0)
624 if (nafter > ndigits)
625 i = ndigits;
626 else
627 i = nafter;
629 memcpy (put, digits, i);
630 while (i < nafter)
631 put[i++] = '0';
633 digits += i;
634 ndigits -= i;
635 put += nafter;
638 /* Set the exponent. */
639 if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
641 if (expchar != ' ')
643 *(put++) = expchar;
644 edigits--;
646 snprintf (buffer, size, "%+0*d", edigits, e);
647 memcpy (put, buffer, edigits);
648 put += edigits;
651 if (dtp->u.p.no_leading_blank)
653 memset (put , ' ' , nblanks);
654 dtp->u.p.no_leading_blank = 0;
655 put += nblanks;
658 if (npad > 0 && !dtp->u.p.g0_no_blanks)
660 memset (put , ' ' , npad);
661 put += npad;
664 /* NULL terminate the string. */
665 *put = '\0';
667 return;
671 /* Write "Infinite" or "Nan" as appropriate for the given format. */
673 static void
674 build_infnan_string (st_parameter_dt *dtp, const fnode *f, int isnan_flag,
675 int sign_bit, char *p, size_t *len)
677 char fin;
678 int nb = 0;
679 sign_t sign;
680 int mark;
682 if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
684 sign = calculate_sign (dtp, sign_bit);
685 mark = (sign == S_PLUS || sign == S_MINUS) ? 8 : 7;
687 nb = f->u.real.w;
688 *len = nb;
690 /* If the field width is zero, the processor must select a width
691 not zero. 4 is chosen to allow output of '-Inf' or '+Inf' */
693 if ((nb == 0) || dtp->u.p.g0_no_blanks)
695 if (isnan_flag)
696 nb = 3;
697 else
698 nb = (sign == S_PLUS || sign == S_MINUS) ? 4 : 3;
699 *len = nb;
702 p[*len] = '\0';
703 if (nb < 3)
705 memset (p, '*', nb);
706 return;
709 memset(p, ' ', nb);
711 if (!isnan_flag)
713 if (sign_bit)
715 /* If the sign is negative and the width is 3, there is
716 insufficient room to output '-Inf', so output asterisks */
717 if (nb == 3)
719 memset (p, '*', nb);
720 return;
722 /* The negative sign is mandatory */
723 fin = '-';
725 else
726 /* The positive sign is optional, but we output it for
727 consistency */
728 fin = '+';
730 if (nb > mark)
731 /* We have room, so output 'Infinity' */
732 memcpy(p + nb - 8, "Infinity", 8);
733 else
734 /* For the case of width equals 8, there is not enough room
735 for the sign and 'Infinity' so we go with 'Inf' */
736 memcpy(p + nb - 3, "Inf", 3);
738 if (sign == S_PLUS || sign == S_MINUS)
740 if (nb < 9 && nb > 3)
741 p[nb - 4] = fin; /* Put the sign in front of Inf */
742 else if (nb > 8)
743 p[nb - 9] = fin; /* Put the sign in front of Infinity */
746 else
747 memcpy(p + nb - 3, "NaN", 3);
752 /* Returns the value of 10**d. */
754 #define CALCULATE_EXP(x) \
755 static GFC_REAL_ ## x \
756 calculate_exp_ ## x (int d)\
758 int i;\
759 GFC_REAL_ ## x r = 1.0;\
760 for (i = 0; i< (d >= 0 ? d : -d); i++)\
761 r *= 10;\
762 r = (d >= 0) ? r : 1.0 / r;\
763 return r;\
766 CALCULATE_EXP(4)
768 CALCULATE_EXP(8)
770 #ifdef HAVE_GFC_REAL_10
771 CALCULATE_EXP(10)
772 #endif
774 #ifdef HAVE_GFC_REAL_16
775 CALCULATE_EXP(16)
776 #endif
777 #undef CALCULATE_EXP
780 /* Define macros to build code for format_float. */
782 /* Note: Before output_float is called, snprintf is used to print to buffer the
783 number in the format +D.DDDDe+ddd.
785 # The result will always contain a decimal point, even if no
786 digits follow it
788 - The converted value is to be left adjusted on the field boundary
790 + A sign (+ or -) always be placed before a number
792 * prec is used as the precision
794 e format: [-]d.ddde±dd where there is one digit before the
795 decimal-point character and the number of digits after it is
796 equal to the precision. The exponent always contains at least two
797 digits; if the value is zero, the exponent is 00. */
800 #define TOKENPASTE(x, y) TOKENPASTE2(x, y)
801 #define TOKENPASTE2(x, y) x ## y
803 #define DTOA(suff,prec,val) TOKENPASTE(DTOA2,suff)(prec,val)
805 #define DTOA2(prec,val) \
806 snprintf (buffer, size, "%+-#.*e", (prec), (val))
808 #define DTOA2L(prec,val) \
809 snprintf (buffer, size, "%+-#.*Le", (prec), (val))
812 #if defined(GFC_REAL_16_IS_FLOAT128)
813 #define DTOA2Q(prec,val) \
814 quadmath_snprintf (buffer, size, "%+-#.*Qe", (prec), (val))
815 #endif
817 #define FDTOA(suff,prec,val) TOKENPASTE(FDTOA2,suff)(prec,val)
819 /* For F format, we print to the buffer with f format. */
820 #define FDTOA2(prec,val) \
821 snprintf (buffer, size, "%+-#.*f", (prec), (val))
823 #define FDTOA2L(prec,val) \
824 snprintf (buffer, size, "%+-#.*Lf", (prec), (val))
827 #if defined(GFC_REAL_16_IS_FLOAT128)
828 #define FDTOA2Q(prec,val) \
829 quadmath_snprintf (buffer, size, "%+-#.*Qf", \
830 (prec), (val))
831 #endif
834 /* EN format is tricky since the number of significant digits depends
835 on the magnitude. Solve it by first printing a temporary value and
836 figure out the number of significant digits from the printed
837 exponent. Values y, 0.95*10.0**e <= y <10.0**e, are rounded to
838 10.0**e even when the final result will not be rounded to 10.0**e.
839 For these values the exponent returned by atoi has to be decremented
840 by one. The values y in the ranges
841 (1000.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*(n+1))
842 (100.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+2)
843 (10.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+1)
844 are correctly rounded respectively to 1.0...0*10.0*(3*(n+1)),
845 100.0...0*10.0*(3*n), and 10.0...0*10.0*(3*n), where 0...0
846 represents d zeroes, by the lines 279 to 297. */
847 #define EN_PREC(x,y)\
849 volatile GFC_REAL_ ## x tmp, one = 1.0;\
850 tmp = * (GFC_REAL_ ## x *)source;\
851 if (isfinite (tmp))\
853 nprinted = DTOA(y,0,tmp);\
854 int e = atoi (&buffer[4]);\
855 if (buffer[1] == '1')\
857 tmp = (calculate_exp_ ## x (-e)) * tmp;\
858 tmp = one - (tmp < 0 ? -tmp : tmp);\
859 if (tmp > 0)\
860 e = e - 1;\
862 nbefore = e%3;\
863 if (nbefore < 0)\
864 nbefore = 3 + nbefore;\
866 else\
867 nprinted = -1;\
870 static int
871 determine_en_precision (st_parameter_dt *dtp, const fnode *f,
872 const char *source, int len)
874 int nprinted;
875 char buffer[10];
876 const size_t size = 10;
877 int nbefore; /* digits before decimal point - 1. */
879 switch (len)
881 case 4:
882 EN_PREC(4,)
883 break;
885 case 8:
886 EN_PREC(8,)
887 break;
889 #ifdef HAVE_GFC_REAL_10
890 case 10:
891 EN_PREC(10,L)
892 break;
893 #endif
894 #ifdef HAVE_GFC_REAL_16
895 case 16:
896 # ifdef GFC_REAL_16_IS_FLOAT128
897 EN_PREC(16,Q)
898 # else
899 EN_PREC(16,L)
900 # endif
901 break;
902 #endif
903 default:
904 internal_error (NULL, "bad real kind");
907 if (nprinted == -1)
908 return -1;
910 int prec = f->u.real.d + nbefore;
911 if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
912 && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
913 prec += 2 * len + 4;
914 return prec;
918 /* Generate corresponding I/O format. and output.
919 The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
920 LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
922 Data Magnitude Equivalent Conversion
923 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
924 m = 0 F(w-n).(d-1), n' '
925 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
926 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
927 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
928 ................ ..........
929 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
930 m >= 10**d-0.5 Ew.d[Ee]
932 notes: for Gw.d , n' ' means 4 blanks
933 for Gw.dEe, n' ' means e+2 blanks
934 for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
935 the asm volatile is required for 32-bit x86 platforms. */
936 #define FORMAT_FLOAT(x,y)\
938 int npad = 0;\
939 GFC_REAL_ ## x m;\
940 m = * (GFC_REAL_ ## x *)source;\
941 sign_bit = signbit (m);\
942 if (!isfinite (m))\
944 build_infnan_string (dtp, f, isnan (m), sign_bit, result, res_len);\
945 return;\
947 m = sign_bit ? -m : m;\
948 zero_flag = (m == 0.0);\
949 if (f->format == FMT_G)\
951 int e = f->u.real.e;\
952 int d = f->u.real.d;\
953 int w = f->u.real.w;\
954 fnode newf;\
955 GFC_REAL_ ## x exp_d, r = 0.5, r_sc;\
956 int low, high, mid;\
957 int ubound, lbound;\
958 int save_scale_factor;\
959 volatile GFC_REAL_ ## x temp;\
960 save_scale_factor = dtp->u.p.scale_factor;\
961 switch (dtp->u.p.current_unit->round_status)\
963 case ROUND_ZERO:\
964 r = sign_bit ? 1.0 : 0.0;\
965 break;\
966 case ROUND_UP:\
967 r = 1.0;\
968 break;\
969 case ROUND_DOWN:\
970 r = 0.0;\
971 break;\
972 default:\
973 break;\
975 exp_d = calculate_exp_ ## x (d);\
976 r_sc = (1 - r / exp_d);\
977 temp = 0.1 * r_sc;\
978 if ((m > 0.0 && ((m < temp) || (r >= (exp_d - m))))\
979 || ((m == 0.0) && !(compile_options.allow_std\
980 & (GFC_STD_F2003 | GFC_STD_F2008)))\
981 || d == 0)\
983 newf.format = FMT_E;\
984 newf.u.real.w = w;\
985 newf.u.real.d = d - comp_d;\
986 newf.u.real.e = e;\
987 npad = 0;\
988 precision = determine_precision (dtp, &newf, x);\
989 nprinted = DTOA(y,precision,m);\
991 else \
993 mid = 0;\
994 low = 0;\
995 high = d + 1;\
996 lbound = 0;\
997 ubound = d + 1;\
998 while (low <= high)\
1000 mid = (low + high) / 2;\
1001 temp = (calculate_exp_ ## x (mid - 1) * r_sc);\
1002 if (m < temp)\
1004 ubound = mid;\
1005 if (ubound == lbound + 1)\
1006 break;\
1007 high = mid - 1;\
1009 else if (m > temp)\
1011 lbound = mid;\
1012 if (ubound == lbound + 1)\
1014 mid ++;\
1015 break;\
1017 low = mid + 1;\
1019 else\
1021 mid++;\
1022 break;\
1025 npad = e <= 0 ? 4 : e + 2;\
1026 npad = npad >= w ? w - 1 : npad;\
1027 npad = dtp->u.p.g0_no_blanks ? 0 : npad;\
1028 newf.format = FMT_F;\
1029 newf.u.real.w = w - npad;\
1030 newf.u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
1031 dtp->u.p.scale_factor = 0;\
1032 precision = determine_precision (dtp, &newf, x);\
1033 nprinted = FDTOA(y,precision,m);\
1035 build_float_string (dtp, &newf, buffer, size, nprinted, precision,\
1036 sign_bit, zero_flag, npad, result, res_len);\
1037 dtp->u.p.scale_factor = save_scale_factor;\
1039 else\
1041 if (f->format == FMT_F)\
1042 nprinted = FDTOA(y,precision,m);\
1043 else\
1044 nprinted = DTOA(y,precision,m);\
1045 build_float_string (dtp, f, buffer, size, nprinted, precision,\
1046 sign_bit, zero_flag, npad, result, res_len);\
1050 /* Output a real number according to its format. */
1053 static void
1054 get_float_string (st_parameter_dt *dtp, const fnode *f, const char *source,
1055 int kind, int comp_d, char *buffer, int precision,
1056 size_t size, char *result, size_t *res_len)
1058 int sign_bit, nprinted;
1059 bool zero_flag;
1061 switch (kind)
1063 case 4:
1064 FORMAT_FLOAT(4,)
1065 break;
1067 case 8:
1068 FORMAT_FLOAT(8,)
1069 break;
1071 #ifdef HAVE_GFC_REAL_10
1072 case 10:
1073 FORMAT_FLOAT(10,L)
1074 break;
1075 #endif
1076 #ifdef HAVE_GFC_REAL_16
1077 case 16:
1078 # ifdef GFC_REAL_16_IS_FLOAT128
1079 FORMAT_FLOAT(16,Q)
1080 # else
1081 FORMAT_FLOAT(16,L)
1082 # endif
1083 break;
1084 #endif
1085 default:
1086 internal_error (NULL, "bad real kind");
1088 return;