OSDN Git Service

2e2b4d87bf478a4432e2bdd6c2c722ddcf990a01
[pf3gnuchains/gcc-fork.git] / libgfortran / io / write_float.def
1 /* Copyright (C) 2007, 2008, 2009, 2010, 2011 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
5
6 This file is part of the GNU Fortran runtime library (libgfortran).
7
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.
12
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.
17
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.
21
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/>.  */
26
27 #include "config.h"
28
29 typedef enum
30 { S_NONE, S_MINUS, S_PLUS }
31 sign_t;
32
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.  */
35
36 static sign_t
37 calculate_sign (st_parameter_dt *dtp, int negative_flag)
38 {
39   sign_t s = S_NONE;
40
41   if (negative_flag)
42     s = S_MINUS;
43   else
44     switch (dtp->u.p.sign_status)
45       {
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;
56       }
57
58   return s;
59 }
60
61
62 /* Output a real number according to its format which is FMT_G free.  */
63
64 static try
65 output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, 
66               int sign_bit, bool zero_flag, int ndigits, int edigits)
67 {
68   char *out;
69   char *digits;
70   int e;
71   char expchar, rchar;
72   format_token ft;
73   int w;
74   int d;
75   /* Number of digits before the decimal point.  */
76   int nbefore;
77   /* Number of zeros after the decimal point.  */
78   int nzero;
79   /* Number of digits after the decimal point.  */
80   int nafter;
81   /* Number of zeros after the decimal point, whatever the precision.  */
82   int nzero_real;
83   int leadzero;
84   int nblanks;
85   int i;
86   sign_t sign;
87
88   ft = f->format;
89   w = f->u.real.w;
90   d = f->u.real.d;
91
92   rchar = '5';
93   nzero_real = -1;
94
95   /* We should always know the field width and precision.  */
96   if (d < 0)
97     internal_error (&dtp->common, "Unspecified precision");
98
99   sign = calculate_sign (dtp, sign_bit);
100   
101   /* The following code checks the given string has punctuation in the correct
102      places.  Uncomment if needed for debugging.
103      if (d != 0 && ((buffer[2] != '.' && buffer[2] != ',')
104                     || buffer[ndigits + 2] != 'e'))
105        internal_error (&dtp->common, "printf is broken");  */
106
107   /* Read the exponent back in.  */
108   e = atoi (&buffer[ndigits + 3]) + 1;
109
110   /* Make sure zero comes out as 0.0e0.   */
111   if (zero_flag)
112     e = 0;
113
114   /* Normalize the fractional component.  */
115   buffer[2] = buffer[1];
116   digits = &buffer[2];
117
118   /* Figure out where to place the decimal point.  */
119   switch (ft)
120     {
121     case FMT_F:
122       if (d == 0 && e <= 0 && dtp->u.p.scale_factor == 0)
123         {
124           memmove (digits + 1, digits, ndigits - 1);
125           digits[0] = '0';
126           e++;
127         }
128
129       nbefore = e + dtp->u.p.scale_factor;
130       if (nbefore < 0)
131         {
132           nzero = -nbefore;
133           nzero_real = nzero;
134           if (nzero > d)
135             nzero = d;
136           nafter = d - nzero;
137           nbefore = 0;
138         }
139       else
140         {
141           nzero = 0;
142           nafter = d;
143         }
144       expchar = 0;
145       break;
146
147     case FMT_E:
148     case FMT_D:
149       i = dtp->u.p.scale_factor;
150       if (d <= 0 && i == 0)
151         {
152           generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
153                           "greater than zero in format specifier 'E' or 'D'");
154           return FAILURE;
155         }
156       if (i <= -d || i >= d + 2)
157         {
158           generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
159                           "out of range in format specifier 'E' or 'D'");
160           return FAILURE;
161         }
162
163       if (!zero_flag)
164         e -= i;
165       if (i < 0)
166         {
167           nbefore = 0;
168           nzero = -i;
169           nafter = d + i;
170         }
171       else if (i > 0)
172         {
173           nbefore = i;
174           nzero = 0;
175           nafter = (d - i) + 1;
176         }
177       else /* i == 0 */
178         {
179           nbefore = 0;
180           nzero = 0;
181           nafter = d;
182         }
183
184       if (ft == FMT_E)
185         expchar = 'E';
186       else
187         expchar = 'D';
188       break;
189
190     case FMT_EN:
191       /* The exponent must be a multiple of three, with 1-3 digits before
192          the decimal point.  */
193       if (!zero_flag)
194         e--;
195       if (e >= 0)
196         nbefore = e % 3;
197       else
198         {
199           nbefore = (-e) % 3;
200           if (nbefore != 0)
201             nbefore = 3 - nbefore;
202         }
203       e -= nbefore;
204       nbefore++;
205       nzero = 0;
206       nafter = d;
207       expchar = 'E';
208       break;
209
210     case FMT_ES:
211       if (!zero_flag)
212         e--;
213       nbefore = 1;
214       nzero = 0;
215       nafter = d;
216       expchar = 'E';
217       break;
218
219     default:
220       /* Should never happen.  */
221       internal_error (&dtp->common, "Unexpected format token");
222     }
223
224   if (zero_flag)
225     goto skip;
226   /* Round the value.  The value being rounded is an unsigned magnitude.
227      The ROUND_COMPATIBLE is rounding away from zero when there is a tie.  */
228   switch (dtp->u.p.current_unit->round_status)
229     {
230       case ROUND_ZERO: /* Do nothing and truncation occurs.  */
231         goto skip;
232       case ROUND_UP:
233         if (sign_bit)
234           goto skip;
235         rchar = '0';
236         break;
237       case ROUND_DOWN:
238         if (!sign_bit)
239           goto skip;
240         rchar = '0';
241         break;
242       case ROUND_NEAREST:
243         /* Round compatible unless there is a tie. A tie is a 5 with
244            all trailing zero's.  */
245         i = nafter + nbefore;
246         if (digits[i] == '5')
247           {
248             for(i++ ; i < ndigits; i++)
249               {
250                 if (digits[i] != '0')
251                   goto do_rnd;
252               }
253             /* It is a  tie so round to even.  */
254             switch (digits[nafter + nbefore - 1])
255               {
256                 case '1':
257                 case '3':
258                 case '5':
259                 case '7':
260                 case '9':
261                   /* If odd, round away from zero to even.  */
262                   break;
263                 default:
264                   /* If even, skip rounding, truncate to even.  */
265                   goto skip;
266               }
267           }
268          /* Fall through.  */ 
269       case ROUND_PROCDEFINED:
270       case ROUND_UNSPECIFIED:
271       case ROUND_COMPATIBLE:
272         rchar = '5';
273         /* Just fall through and do the actual rounding.  */
274     }
275     
276   do_rnd:
277  
278   if (nbefore + nafter == 0)
279     {
280       ndigits = 0;
281       if (nzero_real == d && digits[0] >= rchar)
282         {
283           /* We rounded to zero but shouldn't have */
284           nzero--;
285           nafter = 1;
286           digits[0] = '1';
287           ndigits = 1;
288         }
289     }
290   else if (nbefore + nafter < ndigits)
291     {
292       i = ndigits = nbefore + nafter;
293       if (d == 0 && digits[1] == '0')
294         goto skip;
295       if (digits[i] >= rchar)
296         {
297           /* Propagate the carry.  */
298           for (i--; i >= 0; i--)
299             {
300               if (digits[i] != '9')
301                 {
302                   digits[i]++;
303                   break;
304                 }
305               digits[i] = '0';
306             }
307
308           if (i < 0)
309             {
310               /* The carry overflowed.  Fortunately we have some spare
311                  space at the start of the buffer.  We may discard some
312                  digits, but this is ok because we already know they are
313                  zero.  */
314               digits--;
315               digits[0] = '1';
316               if (ft == FMT_F)
317                 {
318                   if (nzero > 0)
319                     {
320                       nzero--;
321                       nafter++;
322                     }
323                   else
324                     nbefore++;
325                 }
326               else if (ft == FMT_EN)
327                 {
328                   nbefore++;
329                   if (nbefore == 4)
330                     {
331                       nbefore = 1;
332                       e += 3;
333                     }
334                 }
335               else
336                 e++;
337             }
338         }
339     }
340
341   skip:
342
343   /* Calculate the format of the exponent field.  */
344   if (expchar)
345     {
346       edigits = 1;
347       for (i = abs (e); i >= 10; i /= 10)
348         edigits++;
349
350       if (f->u.real.e < 0)
351         {
352           /* Width not specified.  Must be no more than 3 digits.  */
353           if (e > 999 || e < -999)
354             edigits = -1;
355           else
356             {
357               edigits = 4;
358               if (e > 99 || e < -99)
359                 expchar = ' ';
360             }
361         }
362       else
363         {
364           /* Exponent width specified, check it is wide enough.  */
365           if (edigits > f->u.real.e)
366             edigits = -1;
367           else
368             edigits = f->u.real.e + 2;
369         }
370     }
371   else
372     edigits = 0;
373
374   /* Scan the digits string and count the number of zeros.  If we make it
375      all the way through the loop, we know the value is zero after the
376      rounding completed above.  */
377   for (i = 0; i < ndigits; i++)
378     {
379       if (digits[i] != '0')
380         break;
381     }
382
383   /* To format properly, we need to know if the rounded result is zero and if
384      so, we set the zero_flag which may have been already set for
385      actual zero.  */
386   if (i == ndigits)
387     {
388       zero_flag = true;
389       /* The output is zero, so set the sign according to the sign bit unless
390          -fno-sign-zero was specified.  */
391       if (compile_options.sign_zero == 1)
392         sign = calculate_sign (dtp, sign_bit);
393       else
394         sign = calculate_sign (dtp, 0);
395     }
396
397   /* Pick a field size if none was specified, taking into account small
398      values that may have been rounded to zero.  */
399   if (w <= 0)
400     {
401       if (zero_flag)
402         w = d + (sign != S_NONE ? 2 : 1) + (d == 0 ? 1 : 0);
403       else
404         {
405           w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1);
406           w = w == 1 ? 2 : w;
407         }
408     }
409   
410   /* Work out how much padding is needed.  */
411   nblanks = w - (nbefore + nzero + nafter + edigits + 1);
412   if (sign != S_NONE)
413     nblanks--;
414
415   if (dtp->u.p.g0_no_blanks)
416     {
417       w -= nblanks;
418       nblanks = 0;
419     }
420
421   /* Create the ouput buffer.  */
422   out = write_block (dtp, w);
423   if (out == NULL)
424     return FAILURE;
425
426   /* Check the value fits in the specified field width.  */
427   if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE))
428     {
429       if (unlikely (is_char4_unit (dtp)))
430         {
431           gfc_char4_t *out4 = (gfc_char4_t *) out;
432           memset4 (out4, '*', w);
433           return FAILURE;
434         }
435       star_fill (out, w);
436       return FAILURE;
437     }
438
439   /* See if we have space for a zero before the decimal point.  */
440   if (nbefore == 0 && nblanks > 0)
441     {
442       leadzero = 1;
443       nblanks--;
444     }
445   else
446     leadzero = 0;
447
448   /* For internal character(kind=4) units, we duplicate the code used for
449      regular output slightly modified.  This needs to be maintained
450      consistent with the regular code that follows this block.  */
451   if (unlikely (is_char4_unit (dtp)))
452     {
453       gfc_char4_t *out4 = (gfc_char4_t *) out;
454       /* Pad to full field width.  */
455
456       if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
457         {
458           memset4 (out4, ' ', nblanks);
459           out4 += nblanks;
460         }
461
462       /* Output the initial sign (if any).  */
463       if (sign == S_PLUS)
464         *(out4++) = '+';
465       else if (sign == S_MINUS)
466         *(out4++) = '-';
467
468       /* Output an optional leading zero.  */
469       if (leadzero)
470         *(out4++) = '0';
471
472       /* Output the part before the decimal point, padding with zeros.  */
473       if (nbefore > 0)
474         {
475           if (nbefore > ndigits)
476             {
477               i = ndigits;
478               memcpy4 (out4, digits, i);
479               ndigits = 0;
480               while (i < nbefore)
481                 out4[i++] = '0';
482             }
483           else
484             {
485               i = nbefore;
486               memcpy4 (out4, digits, i);
487               ndigits -= i;
488             }
489
490           digits += i;
491           out4 += nbefore;
492         }
493
494       /* Output the decimal point.  */
495       *(out4++) = dtp->u.p.current_unit->decimal_status
496                     == DECIMAL_POINT ? '.' : ',';
497
498       /* Output leading zeros after the decimal point.  */
499       if (nzero > 0)
500         {
501           for (i = 0; i < nzero; i++)
502             *(out4++) = '0';
503         }
504
505       /* Output digits after the decimal point, padding with zeros.  */
506       if (nafter > 0)
507         {
508           if (nafter > ndigits)
509             i = ndigits;
510           else
511             i = nafter;
512
513           memcpy4 (out4, digits, i);
514           while (i < nafter)
515             out4[i++] = '0';
516
517           digits += i;
518           ndigits -= i;
519           out4 += nafter;
520         }
521
522       /* Output the exponent.  */
523       if (expchar)
524         {
525           if (expchar != ' ')
526             {
527               *(out4++) = expchar;
528               edigits--;
529             }
530           snprintf (buffer, size, "%+0*d", edigits, e);
531           memcpy4 (out4, buffer, edigits);
532         }
533
534       if (dtp->u.p.no_leading_blank)
535         {
536           out4 += edigits;
537           memset4 (out4, ' ' , nblanks);
538           dtp->u.p.no_leading_blank = 0;
539         }
540       return SUCCESS;
541     } /* End of character(kind=4) internal unit code.  */
542
543   /* Pad to full field width.  */
544
545   if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
546     {
547       memset (out, ' ', nblanks);
548       out += nblanks;
549     }
550
551   /* Output the initial sign (if any).  */
552   if (sign == S_PLUS)
553     *(out++) = '+';
554   else if (sign == S_MINUS)
555     *(out++) = '-';
556
557   /* Output an optional leading zero.  */
558   if (leadzero)
559     *(out++) = '0';
560
561   /* Output the part before the decimal point, padding with zeros.  */
562   if (nbefore > 0)
563     {
564       if (nbefore > ndigits)
565         {
566           i = ndigits;
567           memcpy (out, digits, i);
568           ndigits = 0;
569           while (i < nbefore)
570             out[i++] = '0';
571         }
572       else
573         {
574           i = nbefore;
575           memcpy (out, digits, i);
576           ndigits -= i;
577         }
578
579       digits += i;
580       out += nbefore;
581     }
582
583   /* Output the decimal point.  */
584   *(out++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
585
586   /* Output leading zeros after the decimal point.  */
587   if (nzero > 0)
588     {
589       for (i = 0; i < nzero; i++)
590         *(out++) = '0';
591     }
592
593   /* Output digits after the decimal point, padding with zeros.  */
594   if (nafter > 0)
595     {
596       if (nafter > ndigits)
597         i = ndigits;
598       else
599         i = nafter;
600
601       memcpy (out, digits, i);
602       while (i < nafter)
603         out[i++] = '0';
604
605       digits += i;
606       ndigits -= i;
607       out += nafter;
608     }
609
610   /* Output the exponent.  */
611   if (expchar)
612     {
613       if (expchar != ' ')
614         {
615           *(out++) = expchar;
616           edigits--;
617         }
618       snprintf (buffer, size, "%+0*d", edigits, e);
619       memcpy (out, buffer, edigits);
620     }
621
622   if (dtp->u.p.no_leading_blank)
623     {
624       out += edigits;
625       memset( out , ' ' , nblanks );
626       dtp->u.p.no_leading_blank = 0;
627     }
628
629 #undef STR
630 #undef STR1
631 #undef MIN_FIELD_WIDTH
632   return SUCCESS;
633 }
634
635
636 /* Write "Infinite" or "Nan" as appropriate for the given format.  */
637
638 static void
639 write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit)
640 {
641   char * p, fin;
642   int nb = 0;
643   sign_t sign;
644   int mark;
645
646   if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
647     {
648       sign = calculate_sign (dtp, sign_bit);
649       mark = (sign == S_PLUS || sign == S_MINUS) ? 8 : 7;
650
651       nb =  f->u.real.w;
652
653       /* If the field width is zero, the processor must select a width 
654          not zero.  4 is chosen to allow output of '-Inf' or '+Inf' */
655      
656       if ((nb == 0) || dtp->u.p.g0_no_blanks)
657         {
658           if (isnan_flag)
659             nb = 3;
660           else
661             nb = (sign == S_PLUS || sign == S_MINUS) ? 4 : 3;
662         }
663       p = write_block (dtp, nb);
664       if (p == NULL)
665         return;
666       if (nb < 3)
667         {
668           if (unlikely (is_char4_unit (dtp)))
669             {
670               gfc_char4_t *p4 = (gfc_char4_t *) p;
671               memset4 (p4, '*', nb);
672             }
673           else
674             memset (p, '*', nb);
675           return;
676         }
677
678       if (unlikely (is_char4_unit (dtp)))
679         {
680           gfc_char4_t *p4 = (gfc_char4_t *) p;
681           memset4 (p4, ' ', nb);
682         }
683       else
684         memset(p, ' ', nb);
685
686       if (!isnan_flag)
687         {
688           if (sign_bit)
689             {
690               /* If the sign is negative and the width is 3, there is
691                  insufficient room to output '-Inf', so output asterisks */
692               if (nb == 3)
693                 {
694                   if (unlikely (is_char4_unit (dtp)))
695                     {
696                       gfc_char4_t *p4 = (gfc_char4_t *) p;
697                       memset4 (p4, '*', nb);
698                     }
699                   else
700                     memset (p, '*', nb);
701                   return;
702                 }
703               /* The negative sign is mandatory */
704               fin = '-';
705             }    
706           else
707             /* The positive sign is optional, but we output it for
708                consistency */
709             fin = '+';
710             
711           if (unlikely (is_char4_unit (dtp)))
712             {
713               gfc_char4_t *p4 = (gfc_char4_t *) p;
714
715               if (nb > mark)
716                 /* We have room, so output 'Infinity' */
717                 memcpy4 (p4 + nb - 8, "Infinity", 8);
718               else
719                 /* For the case of width equals mark, there is not enough room
720                    for the sign and 'Infinity' so we go with 'Inf' */
721                 memcpy4 (p4 + nb - 3, "Inf", 3);
722
723               if (sign == S_PLUS || sign == S_MINUS)
724                 {
725                   if (nb < 9 && nb > 3)
726                     /* Put the sign in front of Inf */
727                     p4[nb - 4] = (gfc_char4_t) fin;
728                   else if (nb > 8)
729                     /* Put the sign in front of Infinity */
730                     p4[nb - 9] = (gfc_char4_t) fin;
731                 }
732               return;
733             }
734
735           if (nb > mark)
736             /* We have room, so output 'Infinity' */
737             memcpy(p + nb - 8, "Infinity", 8);
738           else
739             /* For the case of width equals 8, there is not enough room
740                for the sign and 'Infinity' so we go with 'Inf' */
741             memcpy(p + nb - 3, "Inf", 3);
742
743           if (sign == S_PLUS || sign == S_MINUS)
744             {
745               if (nb < 9 && nb > 3)
746                 p[nb - 4] = fin;  /* Put the sign in front of Inf */
747               else if (nb > 8)
748                 p[nb - 9] = fin;  /* Put the sign in front of Infinity */
749             }
750         }
751       else
752         {
753           if (unlikely (is_char4_unit (dtp)))
754             {
755               gfc_char4_t *p4 = (gfc_char4_t *) p;
756               memcpy4 (p4 + nb - 3, "NaN", 3);
757             }
758           else
759             memcpy(p + nb - 3, "NaN", 3);
760         }
761       return;
762     }
763 }
764
765
766 /* Returns the value of 10**d.  */
767
768 #define CALCULATE_EXP(x) \
769 inline static GFC_REAL_ ## x \
770 calculate_exp_ ## x  (int d)\
771 {\
772   int i;\
773   GFC_REAL_ ## x r = 1.0;\
774   for (i = 0; i< (d >= 0 ? d : -d); i++)\
775     r *= 10;\
776   r = (d >= 0) ? r : 1.0 / r;\
777   return r;\
778 }
779
780 CALCULATE_EXP(4)
781
782 CALCULATE_EXP(8)
783
784 #ifdef HAVE_GFC_REAL_10
785 CALCULATE_EXP(10)
786 #endif
787
788 #ifdef HAVE_GFC_REAL_16
789 CALCULATE_EXP(16)
790 #endif
791 #undef CALCULATE_EXP
792
793 /* Generate corresponding I/O format for FMT_G and output.
794    The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
795    LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
796
797    Data Magnitude                              Equivalent Conversion
798    0< m < 0.1-0.5*10**(-d-1)                   Ew.d[Ee]
799    m = 0                                       F(w-n).(d-1), n' '
800    0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d)     F(w-n).d, n' '
801    1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1)      F(w-n).(d-1), n' '
802    10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2)  F(w-n).(d-2), n' '
803    ................                           ..........
804    10**(d-1)-0.5*10**(-1)<= m <10**d-0.5       F(w-n).0,n(' ')
805    m >= 10**d-0.5                              Ew.d[Ee]
806
807    notes: for Gw.d ,  n' ' means 4 blanks
808           for Gw.dEe, n' ' means e+2 blanks
809           for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
810           the asm volatile is required for 32-bit x86 platforms.  */
811
812 #define OUTPUT_FLOAT_FMT_G(x) \
813 static void \
814 output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
815                       GFC_REAL_ ## x m, char *buffer, size_t size, \
816                       int sign_bit, bool zero_flag, int ndigits, \
817                       int edigits, int comp_d) \
818 { \
819   int e = f->u.real.e;\
820   int d = f->u.real.d;\
821   int w = f->u.real.w;\
822   fnode *newf;\
823   GFC_REAL_ ## x rexp_d, r = 0.5;\
824   int low, high, mid;\
825   int ubound, lbound;\
826   char *p, pad = ' ';\
827   int save_scale_factor, nb = 0;\
828   try result;\
829 \
830   save_scale_factor = dtp->u.p.scale_factor;\
831   newf = (fnode *) get_mem (sizeof (fnode));\
832 \
833   switch (dtp->u.p.current_unit->round_status)\
834     {\
835       case ROUND_ZERO:\
836         r = sign_bit ? 1.0 : 0.0;\
837         break;\
838       case ROUND_UP:\
839         r = 1.0;\
840         break;\
841       case ROUND_DOWN:\
842         r = 0.0;\
843         break;\
844       default:\
845         break;\
846     }\
847 \
848   rexp_d = calculate_exp_ ## x (-d);\
849   if ((m > 0.0 && ((m < 0.1 - 0.1 * r * rexp_d) || (rexp_d * (m + r) >= 1.0)))\
850       || ((m == 0.0) && !(compile_options.allow_std\
851                           & (GFC_STD_F2003 | GFC_STD_F2008))))\
852     { \
853       newf->format = FMT_E;\
854       newf->u.real.w = w;\
855       newf->u.real.d = d - comp_d;\
856       newf->u.real.e = e;\
857       nb = 0;\
858       goto finish;\
859     }\
860 \
861   mid = 0;\
862   low = 0;\
863   high = d + 1;\
864   lbound = 0;\
865   ubound = d + 1;\
866 \
867   while (low <= high)\
868     { \
869       volatile GFC_REAL_ ## x temp;\
870       mid = (low + high) / 2;\
871 \
872       temp = (calculate_exp_ ## x (mid - 1) * (1 - r * rexp_d));\
873 \
874       if (m < temp)\
875         { \
876           ubound = mid;\
877           if (ubound == lbound + 1)\
878             break;\
879           high = mid - 1;\
880         }\
881       else if (m > temp)\
882         { \
883           lbound = mid;\
884           if (ubound == lbound + 1)\
885             { \
886               mid ++;\
887               break;\
888             }\
889           low = mid + 1;\
890         }\
891       else\
892         {\
893           mid++;\
894           break;\
895         }\
896     }\
897 \
898   nb = e <= 0 ? 4 : e + 2;\
899   nb = nb >= w ? w - 1 : nb;\
900   newf->format = FMT_F;\
901   newf->u.real.w = w - nb;\
902   newf->u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
903   dtp->u.p.scale_factor = 0;\
904 \
905  finish:\
906   result = output_float (dtp, newf, buffer, size, sign_bit, zero_flag, \
907                          ndigits, edigits);\
908   dtp->u.p.scale_factor = save_scale_factor;\
909 \
910   free (newf);\
911 \
912   if (nb > 0 && !dtp->u.p.g0_no_blanks)\
913     {\
914       p = write_block (dtp, nb);\
915       if (p == NULL)\
916         return;\
917       if (result == FAILURE)\
918         pad = '*';\
919       if (unlikely (is_char4_unit (dtp)))\
920         {\
921           gfc_char4_t *p4 = (gfc_char4_t *) p;\
922           memset4 (p4, pad, nb);\
923         }\
924       else \
925         memset (p, pad, nb);\
926     }\
927 }\
928
929 OUTPUT_FLOAT_FMT_G(4)
930
931 OUTPUT_FLOAT_FMT_G(8)
932
933 #ifdef HAVE_GFC_REAL_10
934 OUTPUT_FLOAT_FMT_G(10)
935 #endif
936
937 #ifdef HAVE_GFC_REAL_16
938 OUTPUT_FLOAT_FMT_G(16)
939 #endif
940
941 #undef OUTPUT_FLOAT_FMT_G
942
943
944 /* Define a macro to build code for write_float.  */
945
946   /* Note: Before output_float is called, snprintf is used to print to buffer the
947      number in the format +D.DDDDe+ddd. For an N digit exponent, this gives us
948      (MIN_FIELD_WIDTH-5)-N digits after the decimal point, plus another one
949      before the decimal point.
950
951      #   The result will always contain a decimal point, even if no
952          digits follow it
953
954      -   The converted value is to be left adjusted on the field boundary
955
956      +   A sign (+ or -) always be placed before a number
957
958      MIN_FIELD_WIDTH  minimum field width
959
960      *   (ndigits-1) is used as the precision
961
962      e format: [-]d.ddde±dd where there is one digit before the
963        decimal-point character and the number of digits after it is
964        equal to the precision. The exponent always contains at least two
965        digits; if the value is zero, the exponent is 00.  */
966
967 #define DTOA \
968 snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
969           "e", ndigits - 1, tmp);
970
971 #define DTOAL \
972 snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
973           "Le", ndigits - 1, tmp);
974
975
976 #if defined(GFC_REAL_16_IS_FLOAT128)
977 #define DTOAQ \
978 __qmath_(quadmath_snprintf) (buffer, sizeof buffer, \
979                              "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
980                              "Qe", ndigits - 1, tmp);
981 #endif
982
983 #define WRITE_FLOAT(x,y)\
984 {\
985         GFC_REAL_ ## x tmp;\
986         tmp = * (GFC_REAL_ ## x *)source;\
987         sign_bit = signbit (tmp);\
988         if (!isfinite (tmp))\
989           { \
990             write_infnan (dtp, f, isnan (tmp), sign_bit);\
991             return;\
992           }\
993         tmp = sign_bit ? -tmp : tmp;\
994         zero_flag = (tmp == 0.0);\
995 \
996         DTOA ## y\
997 \
998         if (f->format != FMT_G)\
999           output_float (dtp, f, buffer, size, sign_bit, zero_flag, ndigits, \
1000                         edigits);\
1001         else \
1002           output_float_FMT_G_ ## x (dtp, f, tmp, buffer, size, sign_bit, \
1003                                     zero_flag, ndigits, edigits, comp_d);\
1004 }\
1005
1006 /* Output a real number according to its format.  */
1007
1008 static void
1009 write_float (st_parameter_dt *dtp, const fnode *f, const char *source, \
1010             int len, int comp_d)
1011 {
1012
1013 #if defined(HAVE_GFC_REAL_16) || __LDBL_DIG__ > 18
1014 # define MIN_FIELD_WIDTH 49
1015 #else
1016 # define MIN_FIELD_WIDTH 32
1017 #endif
1018 #define STR(x) STR1(x)
1019 #define STR1(x) #x
1020
1021   /* This must be large enough to accurately hold any value.  */
1022   char buffer[MIN_FIELD_WIDTH+1];
1023   int sign_bit, ndigits, edigits;
1024   bool zero_flag;
1025   size_t size;
1026
1027   size = MIN_FIELD_WIDTH+1;
1028
1029   /* printf pads blanks for us on the exponent so we just need it big enough
1030      to handle the largest number of exponent digits expected.  */
1031   edigits=4;
1032
1033   /* Always convert at full precision to avoid double rounding.  */
1034     ndigits = MIN_FIELD_WIDTH - 4 - edigits;
1035
1036   switch (len)
1037     {
1038     case 4:
1039       WRITE_FLOAT(4,)
1040       break;
1041
1042     case 8:
1043       WRITE_FLOAT(8,)
1044       break;
1045
1046 #ifdef HAVE_GFC_REAL_10
1047     case 10:
1048       WRITE_FLOAT(10,L)
1049       break;
1050 #endif
1051 #ifdef HAVE_GFC_REAL_16
1052     case 16:
1053 # ifdef GFC_REAL_16_IS_FLOAT128
1054       WRITE_FLOAT(16,Q)
1055 # else
1056       WRITE_FLOAT(16,L)
1057 # endif
1058       break;
1059 #endif
1060     default:
1061       internal_error (NULL, "bad real kind");
1062     }
1063 }