Correct type names in fp-int-convert-float*x-timode.c tests.
[official-gcc.git] / libgfortran / io / write_float.def
blob04223c043a345f67e49d6b31fc5d39c41d689a6e
1 /* Copyright (C) 2007-2016 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 /* Make sure the decimal point is a '.'; depending on the
178 locale, this might not be the case otherwise. */
179 digits[nbefore] = '.';
180 if (p != 0)
182 if (p > 0)
184 memmove (digits + nbefore, digits + nbefore + 1, p);
185 digits[nbefore + p] = '.';
186 nbefore += p;
187 nafter = d;
188 nzero = 0;
190 else /* p < 0 */
192 if (nbefore + p >= 0)
194 nzero = 0;
195 memmove (digits + nbefore + p + 1, digits + nbefore + p, -p);
196 nbefore += p;
197 digits[nbefore] = '.';
198 nafter = d;
200 else
202 nzero = -(nbefore + p);
203 memmove (digits + 1, digits, nbefore);
204 nafter = d - nzero;
205 if (nafter == 0 && d > 0)
207 /* This is needed to get the correct rounding. */
208 memmove (digits + 1, digits, ndigits - 1);
209 digits[1] = '0';
210 nafter = 1;
211 nzero = d - 1;
213 else if (nafter < 0)
215 /* Reset digits to 0 in order to get correct rounding
216 towards infinity. */
217 for (i = 0; i < ndigits; i++)
218 digits[i] = '0';
219 digits[ndigits - 1] = '1';
220 nafter = d;
221 nzero = 0;
223 nbefore = 0;
227 else
229 nzero = 0;
230 nafter = d;
233 while (digits[0] == '0' && nbefore > 0)
235 digits++;
236 nbefore--;
237 ndigits--;
240 expchar = 0;
241 /* If we need to do rounding ourselves, get rid of the dot by
242 moving the fractional part. */
243 if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
244 && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
245 memmove (digits + nbefore, digits + nbefore + 1, ndigits - nbefore);
246 break;
248 case FMT_E:
249 case FMT_D:
250 i = dtp->u.p.scale_factor;
251 if (d <= 0 && p == 0)
253 generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
254 "greater than zero in format specifier 'E' or 'D'");
255 return;
257 if (p <= -d || p >= d + 2)
259 generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
260 "out of range in format specifier 'E' or 'D'");
261 return;
264 if (!zero_flag)
265 e -= p;
266 if (p < 0)
268 nbefore = 0;
269 nzero = -p;
270 nafter = d + p;
272 else if (p > 0)
274 nbefore = p;
275 nzero = 0;
276 nafter = (d - p) + 1;
278 else /* p == 0 */
280 nbefore = 0;
281 nzero = 0;
282 nafter = d;
285 if (ft == FMT_E)
286 expchar = 'E';
287 else
288 expchar = 'D';
289 break;
291 case FMT_EN:
292 /* The exponent must be a multiple of three, with 1-3 digits before
293 the decimal point. */
294 if (!zero_flag)
295 e--;
296 if (e >= 0)
297 nbefore = e % 3;
298 else
300 nbefore = (-e) % 3;
301 if (nbefore != 0)
302 nbefore = 3 - nbefore;
304 e -= nbefore;
305 nbefore++;
306 nzero = 0;
307 nafter = d;
308 expchar = 'E';
309 break;
311 case FMT_ES:
312 if (!zero_flag)
313 e--;
314 nbefore = 1;
315 nzero = 0;
316 nafter = d;
317 expchar = 'E';
318 break;
320 default:
321 /* Should never happen. */
322 internal_error (&dtp->common, "Unexpected format token");
325 if (zero_flag)
326 goto skip;
328 /* Round the value. The value being rounded is an unsigned magnitude. */
329 switch (dtp->u.p.current_unit->round_status)
331 /* For processor defined and unspecified rounding we use
332 snprintf to print the exact number of digits needed, and thus
333 let snprintf handle the rounding. On system claiming support
334 for IEEE 754, this ought to be round to nearest, ties to
335 even, corresponding to the Fortran ROUND='NEAREST'. */
336 case ROUND_PROCDEFINED:
337 case ROUND_UNSPECIFIED:
338 case ROUND_ZERO: /* Do nothing and truncation occurs. */
339 goto skip;
340 case ROUND_UP:
341 if (sign_bit)
342 goto skip;
343 goto updown;
344 case ROUND_DOWN:
345 if (!sign_bit)
346 goto skip;
347 goto updown;
348 case ROUND_NEAREST:
349 /* Round compatible unless there is a tie. A tie is a 5 with
350 all trailing zero's. */
351 i = nafter + nbefore;
352 if (digits[i] == '5')
354 for(i++ ; i < ndigits; i++)
356 if (digits[i] != '0')
357 goto do_rnd;
359 /* It is a tie so round to even. */
360 switch (digits[nafter + nbefore - 1])
362 case '1':
363 case '3':
364 case '5':
365 case '7':
366 case '9':
367 /* If odd, round away from zero to even. */
368 break;
369 default:
370 /* If even, skip rounding, truncate to even. */
371 goto skip;
374 /* Fall through. */
375 /* The ROUND_COMPATIBLE is rounding away from zero when there is a tie. */
376 case ROUND_COMPATIBLE:
377 rchar = '5';
378 goto do_rnd;
381 updown:
383 rchar = '0';
384 if (ft != FMT_F && w > 0 && d == 0 && p == 0)
385 nbefore = 1;
386 /* Scan for trailing zeros to see if we really need to round it. */
387 for(i = nbefore + nafter; i < ndigits; i++)
389 if (digits[i] != '0')
390 goto do_rnd;
392 goto skip;
394 do_rnd:
396 if (nbefore + nafter == 0)
397 /* Handle the case Fw.0 and value < 1.0 */
399 ndigits = 0;
400 if (digits[0] >= rchar)
402 /* We rounded to zero but shouldn't have */
403 nbefore = 1;
404 digits--;
405 digits[0] = '1';
406 ndigits = 1;
409 else if (nbefore + nafter < ndigits)
411 i = ndigits = nbefore + nafter;
412 if (digits[i] >= rchar)
414 /* Propagate the carry. */
415 for (i--; i >= 0; i--)
417 if (digits[i] != '9')
419 digits[i]++;
420 break;
422 digits[i] = '0';
425 if (i < 0)
427 /* The carry overflowed. Fortunately we have some spare
428 space at the start of the buffer. We may discard some
429 digits, but this is ok because we already know they are
430 zero. */
431 digits--;
432 digits[0] = '1';
433 if (ft == FMT_F)
435 if (nzero > 0)
437 nzero--;
438 nafter++;
440 else
441 nbefore++;
443 else if (ft == FMT_EN)
445 nbefore++;
446 if (nbefore == 4)
448 nbefore = 1;
449 e += 3;
452 else
453 e++;
458 skip:
460 /* Calculate the format of the exponent field. */
461 if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
463 edigits = 1;
464 for (i = abs (e); i >= 10; i /= 10)
465 edigits++;
467 if (f->u.real.e < 0)
469 /* Width not specified. Must be no more than 3 digits. */
470 if (e > 999 || e < -999)
471 edigits = -1;
472 else
474 edigits = 4;
475 if (e > 99 || e < -99)
476 expchar = ' ';
479 else
481 /* Exponent width specified, check it is wide enough. */
482 if (edigits > f->u.real.e)
483 edigits = -1;
484 else
485 edigits = f->u.real.e + 2;
488 else
489 edigits = 0;
491 /* Scan the digits string and count the number of zeros. If we make it
492 all the way through the loop, we know the value is zero after the
493 rounding completed above. */
494 int hasdot = 0;
495 for (i = 0; i < ndigits + hasdot; i++)
497 if (digits[i] == '.')
498 hasdot = 1;
499 else if (digits[i] != '0')
500 break;
503 /* To format properly, we need to know if the rounded result is zero and if
504 so, we set the zero_flag which may have been already set for
505 actual zero. */
506 if (i == ndigits + hasdot)
508 zero_flag = true;
509 /* The output is zero, so set the sign according to the sign bit unless
510 -fno-sign-zero was specified. */
511 if (compile_options.sign_zero == 1)
512 sign = calculate_sign (dtp, sign_bit);
513 else
514 sign = calculate_sign (dtp, 0);
517 /* Pick a field size if none was specified, taking into account small
518 values that may have been rounded to zero. */
519 if (w <= 0)
521 if (zero_flag)
522 w = d + (sign != S_NONE ? 2 : 1) + (d == 0 ? 1 : 0);
523 else
525 w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1);
526 w = w == 1 ? 2 : w;
530 /* Work out how much padding is needed. */
531 nblanks = w - (nbefore + nzero + nafter + edigits + 1);
532 if (sign != S_NONE)
533 nblanks--;
535 /* See if we have space for a zero before the decimal point. */
536 if (nbefore == 0 && nblanks > 0)
538 leadzero = 1;
539 nblanks--;
541 else
542 leadzero = 0;
544 if (dtp->u.p.g0_no_blanks)
546 w -= nblanks;
547 nblanks = 0;
550 /* Create the final float string. */
551 *len = w + npad;
552 put = result;
554 /* Check the value fits in the specified field width. */
555 if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE))
557 star_fill (put, *len);
558 return;
561 /* Pad to full field width. */
562 if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
564 memset (put, ' ', nblanks);
565 put += nblanks;
568 /* Set the initial sign (if any). */
569 if (sign == S_PLUS)
570 *(put++) = '+';
571 else if (sign == S_MINUS)
572 *(put++) = '-';
574 /* Set an optional leading zero. */
575 if (leadzero)
576 *(put++) = '0';
578 /* Set the part before the decimal point, padding with zeros. */
579 if (nbefore > 0)
581 if (nbefore > ndigits)
583 i = ndigits;
584 memcpy (put, digits, i);
585 ndigits = 0;
586 while (i < nbefore)
587 put[i++] = '0';
589 else
591 i = nbefore;
592 memcpy (put, digits, i);
593 ndigits -= i;
596 digits += i;
597 put += nbefore;
600 /* Set the decimal point. */
601 *(put++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
602 if (ft == FMT_F
603 && (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
604 || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
605 digits++;
607 /* Set leading zeros after the decimal point. */
608 if (nzero > 0)
610 for (i = 0; i < nzero; i++)
611 *(put++) = '0';
614 /* Set digits after the decimal point, padding with zeros. */
615 if (nafter > 0)
617 if (nafter > ndigits)
618 i = ndigits;
619 else
620 i = nafter;
622 memcpy (put, digits, i);
623 while (i < nafter)
624 put[i++] = '0';
626 digits += i;
627 ndigits -= i;
628 put += nafter;
631 /* Set the exponent. */
632 if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
634 if (expchar != ' ')
636 *(put++) = expchar;
637 edigits--;
639 snprintf (buffer, size, "%+0*d", edigits, e);
640 memcpy (put, buffer, edigits);
641 put += edigits;
644 if (dtp->u.p.no_leading_blank)
646 memset (put , ' ' , nblanks);
647 dtp->u.p.no_leading_blank = 0;
648 put += nblanks;
651 if (npad > 0 && !dtp->u.p.g0_no_blanks)
653 memset (put , ' ' , npad);
654 put += npad;
657 /* NULL terminate the string. */
658 *put = '\0';
660 return;
664 /* Write "Infinite" or "Nan" as appropriate for the given format. */
666 static void
667 build_infnan_string (st_parameter_dt *dtp, const fnode *f, int isnan_flag,
668 int sign_bit, char *p, size_t *len)
670 char fin;
671 int nb = 0;
672 sign_t sign;
673 int mark;
675 if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
677 sign = calculate_sign (dtp, sign_bit);
678 mark = (sign == S_PLUS || sign == S_MINUS) ? 8 : 7;
680 nb = f->u.real.w;
681 *len = nb;
683 /* If the field width is zero, the processor must select a width
684 not zero. 4 is chosen to allow output of '-Inf' or '+Inf' */
686 if ((nb == 0) || dtp->u.p.g0_no_blanks)
688 if (isnan_flag)
689 nb = 3;
690 else
691 nb = (sign == S_PLUS || sign == S_MINUS) ? 4 : 3;
692 *len = nb;
695 p[*len] = '\0';
696 if (nb < 3)
698 memset (p, '*', nb);
699 return;
702 memset(p, ' ', nb);
704 if (!isnan_flag)
706 if (sign_bit)
708 /* If the sign is negative and the width is 3, there is
709 insufficient room to output '-Inf', so output asterisks */
710 if (nb == 3)
712 memset (p, '*', nb);
713 return;
715 /* The negative sign is mandatory */
716 fin = '-';
718 else
719 /* The positive sign is optional, but we output it for
720 consistency */
721 fin = '+';
723 if (nb > mark)
724 /* We have room, so output 'Infinity' */
725 memcpy(p + nb - 8, "Infinity", 8);
726 else
727 /* For the case of width equals 8, there is not enough room
728 for the sign and 'Infinity' so we go with 'Inf' */
729 memcpy(p + nb - 3, "Inf", 3);
731 if (sign == S_PLUS || sign == S_MINUS)
733 if (nb < 9 && nb > 3)
734 p[nb - 4] = fin; /* Put the sign in front of Inf */
735 else if (nb > 8)
736 p[nb - 9] = fin; /* Put the sign in front of Infinity */
739 else
740 memcpy(p + nb - 3, "NaN", 3);
745 /* Returns the value of 10**d. */
747 #define CALCULATE_EXP(x) \
748 static GFC_REAL_ ## x \
749 calculate_exp_ ## x (int d)\
751 int i;\
752 GFC_REAL_ ## x r = 1.0;\
753 for (i = 0; i< (d >= 0 ? d : -d); i++)\
754 r *= 10;\
755 r = (d >= 0) ? r : 1.0 / r;\
756 return r;\
759 CALCULATE_EXP(4)
761 CALCULATE_EXP(8)
763 #ifdef HAVE_GFC_REAL_10
764 CALCULATE_EXP(10)
765 #endif
767 #ifdef HAVE_GFC_REAL_16
768 CALCULATE_EXP(16)
769 #endif
770 #undef CALCULATE_EXP
773 /* Define macros to build code for format_float. */
775 /* Note: Before output_float is called, snprintf is used to print to buffer the
776 number in the format +D.DDDDe+ddd.
778 # The result will always contain a decimal point, even if no
779 digits follow it
781 - The converted value is to be left adjusted on the field boundary
783 + A sign (+ or -) always be placed before a number
785 * prec is used as the precision
787 e format: [-]d.ddde±dd where there is one digit before the
788 decimal-point character and the number of digits after it is
789 equal to the precision. The exponent always contains at least two
790 digits; if the value is zero, the exponent is 00. */
793 #define TOKENPASTE(x, y) TOKENPASTE2(x, y)
794 #define TOKENPASTE2(x, y) x ## y
796 #define DTOA(suff,prec,val) TOKENPASTE(DTOA2,suff)(prec,val)
798 #define DTOA2(prec,val) \
799 snprintf (buffer, size, "%+-#.*e", (prec), (val))
801 #define DTOA2L(prec,val) \
802 snprintf (buffer, size, "%+-#.*Le", (prec), (val))
805 #if defined(GFC_REAL_16_IS_FLOAT128)
806 #define DTOA2Q(prec,val) \
807 quadmath_snprintf (buffer, size, "%+-#.*Qe", (prec), (val))
808 #endif
810 #define FDTOA(suff,prec,val) TOKENPASTE(FDTOA2,suff)(prec,val)
812 /* For F format, we print to the buffer with f format. */
813 #define FDTOA2(prec,val) \
814 snprintf (buffer, size, "%+-#.*f", (prec), (val))
816 #define FDTOA2L(prec,val) \
817 snprintf (buffer, size, "%+-#.*Lf", (prec), (val))
820 #if defined(GFC_REAL_16_IS_FLOAT128)
821 #define FDTOA2Q(prec,val) \
822 quadmath_snprintf (buffer, size, "%+-#.*Qf", \
823 (prec), (val))
824 #endif
827 /* EN format is tricky since the number of significant digits depends
828 on the magnitude. Solve it by first printing a temporary value and
829 figure out the number of significant digits from the printed
830 exponent. Values y, 0.95*10.0**e <= y <10.0**e, are rounded to
831 10.0**e even when the final result will not be rounded to 10.0**e.
832 For these values the exponent returned by atoi has to be decremented
833 by one. The values y in the ranges
834 (1000.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*(n+1))
835 (100.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+2)
836 (10.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+1)
837 are correctly rounded respectively to 1.0...0*10.0*(3*(n+1)),
838 100.0...0*10.0*(3*n), and 10.0...0*10.0*(3*n), where 0...0
839 represents d zeroes, by the lines 279 to 297. */
840 #define EN_PREC(x,y)\
842 volatile GFC_REAL_ ## x tmp, one = 1.0;\
843 tmp = * (GFC_REAL_ ## x *)source;\
844 if (isfinite (tmp))\
846 nprinted = DTOA(y,0,tmp);\
847 int e = atoi (&buffer[4]);\
848 if (buffer[1] == '1')\
850 tmp = (calculate_exp_ ## x (-e)) * tmp;\
851 tmp = one - (tmp < 0 ? -tmp : tmp);\
852 if (tmp > 0)\
853 e = e - 1;\
855 nbefore = e%3;\
856 if (nbefore < 0)\
857 nbefore = 3 + nbefore;\
859 else\
860 nprinted = -1;\
863 static int
864 determine_en_precision (st_parameter_dt *dtp, const fnode *f,
865 const char *source, int len)
867 int nprinted;
868 char buffer[10];
869 const size_t size = 10;
870 int nbefore; /* digits before decimal point - 1. */
872 switch (len)
874 case 4:
875 EN_PREC(4,)
876 break;
878 case 8:
879 EN_PREC(8,)
880 break;
882 #ifdef HAVE_GFC_REAL_10
883 case 10:
884 EN_PREC(10,L)
885 break;
886 #endif
887 #ifdef HAVE_GFC_REAL_16
888 case 16:
889 # ifdef GFC_REAL_16_IS_FLOAT128
890 EN_PREC(16,Q)
891 # else
892 EN_PREC(16,L)
893 # endif
894 break;
895 #endif
896 default:
897 internal_error (NULL, "bad real kind");
900 if (nprinted == -1)
901 return -1;
903 int prec = f->u.real.d + nbefore;
904 if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
905 && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
906 prec += 2 * len + 4;
907 return prec;
911 /* Generate corresponding I/O format. and output.
912 The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
913 LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
915 Data Magnitude Equivalent Conversion
916 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
917 m = 0 F(w-n).(d-1), n' '
918 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
919 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
920 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
921 ................ ..........
922 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
923 m >= 10**d-0.5 Ew.d[Ee]
925 notes: for Gw.d , n' ' means 4 blanks
926 for Gw.dEe, n' ' means e+2 blanks
927 for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
928 the asm volatile is required for 32-bit x86 platforms. */
929 #define FORMAT_FLOAT(x,y)\
931 int npad = 0;\
932 GFC_REAL_ ## x m;\
933 m = * (GFC_REAL_ ## x *)source;\
934 sign_bit = signbit (m);\
935 if (!isfinite (m))\
937 build_infnan_string (dtp, f, isnan (m), sign_bit, result, res_len);\
938 return;\
940 m = sign_bit ? -m : m;\
941 zero_flag = (m == 0.0);\
942 if (f->format == FMT_G)\
944 int e = f->u.real.e;\
945 int d = f->u.real.d;\
946 int w = f->u.real.w;\
947 fnode newf;\
948 GFC_REAL_ ## x exp_d, r = 0.5, r_sc;\
949 int low, high, mid;\
950 int ubound, lbound;\
951 int save_scale_factor;\
952 volatile GFC_REAL_ ## x temp;\
953 save_scale_factor = dtp->u.p.scale_factor;\
954 switch (dtp->u.p.current_unit->round_status)\
956 case ROUND_ZERO:\
957 r = sign_bit ? 1.0 : 0.0;\
958 break;\
959 case ROUND_UP:\
960 r = 1.0;\
961 break;\
962 case ROUND_DOWN:\
963 r = 0.0;\
964 break;\
965 default:\
966 break;\
968 exp_d = calculate_exp_ ## x (d);\
969 r_sc = (1 - r / exp_d);\
970 temp = 0.1 * r_sc;\
971 if ((m > 0.0 && ((m < temp) || (r >= (exp_d - m))))\
972 || ((m == 0.0) && !(compile_options.allow_std\
973 & (GFC_STD_F2003 | GFC_STD_F2008)))\
974 || d == 0)\
976 newf.format = FMT_E;\
977 newf.u.real.w = w;\
978 newf.u.real.d = d - comp_d;\
979 newf.u.real.e = e;\
980 npad = 0;\
981 precision = determine_precision (dtp, &newf, x);\
982 nprinted = DTOA(y,precision,m);\
984 else \
986 mid = 0;\
987 low = 0;\
988 high = d + 1;\
989 lbound = 0;\
990 ubound = d + 1;\
991 while (low <= high)\
993 mid = (low + high) / 2;\
994 temp = (calculate_exp_ ## x (mid - 1) * r_sc);\
995 if (m < temp)\
997 ubound = mid;\
998 if (ubound == lbound + 1)\
999 break;\
1000 high = mid - 1;\
1002 else if (m > temp)\
1004 lbound = mid;\
1005 if (ubound == lbound + 1)\
1007 mid ++;\
1008 break;\
1010 low = mid + 1;\
1012 else\
1014 mid++;\
1015 break;\
1018 npad = e <= 0 ? 4 : e + 2;\
1019 npad = npad >= w ? w - 1 : npad;\
1020 npad = dtp->u.p.g0_no_blanks ? 0 : npad;\
1021 newf.format = FMT_F;\
1022 newf.u.real.w = w - npad;\
1023 newf.u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
1024 dtp->u.p.scale_factor = 0;\
1025 precision = determine_precision (dtp, &newf, x);\
1026 nprinted = FDTOA(y,precision,m);\
1028 build_float_string (dtp, &newf, buffer, size, nprinted, precision,\
1029 sign_bit, zero_flag, npad, result, res_len);\
1030 dtp->u.p.scale_factor = save_scale_factor;\
1032 else\
1034 if (f->format == FMT_F)\
1035 nprinted = FDTOA(y,precision,m);\
1036 else\
1037 nprinted = DTOA(y,precision,m);\
1038 build_float_string (dtp, f, buffer, size, nprinted, precision,\
1039 sign_bit, zero_flag, npad, result, res_len);\
1043 /* Output a real number according to its format. */
1046 static void
1047 get_float_string (st_parameter_dt *dtp, const fnode *f, const char *source,
1048 int kind, int comp_d, char *buffer, int precision,
1049 size_t size, char *result, size_t *res_len)
1051 int sign_bit, nprinted;
1052 bool zero_flag;
1054 switch (kind)
1056 case 4:
1057 FORMAT_FLOAT(4,)
1058 break;
1060 case 8:
1061 FORMAT_FLOAT(8,)
1062 break;
1064 #ifdef HAVE_GFC_REAL_10
1065 case 10:
1066 FORMAT_FLOAT(10,L)
1067 break;
1068 #endif
1069 #ifdef HAVE_GFC_REAL_16
1070 case 16:
1071 # ifdef GFC_REAL_16_IS_FLOAT128
1072 FORMAT_FLOAT(16,Q)
1073 # else
1074 FORMAT_FLOAT(16,L)
1075 # endif
1076 break;
1077 #endif
1078 default:
1079 internal_error (NULL, "bad real kind");
1081 return;