xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/io/write_float.def (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1*b1e83836Smrg/* Copyright (C) 2007-2022 Free Software Foundation, Inc.
2181254a7Smrg   Contributed by Andy Vaught
3181254a7Smrg   Write float code factoring to this file by Jerry DeLisle
4181254a7Smrg   F2003 I/O support contributed by Jerry DeLisle
5181254a7Smrg
6181254a7SmrgThis file is part of the GNU Fortran runtime library (libgfortran).
7181254a7Smrg
8181254a7SmrgLibgfortran is free software; you can redistribute it and/or modify
9181254a7Smrgit under the terms of the GNU General Public License as published by
10181254a7Smrgthe Free Software Foundation; either version 3, or (at your option)
11181254a7Smrgany later version.
12181254a7Smrg
13181254a7SmrgLibgfortran is distributed in the hope that it will be useful,
14181254a7Smrgbut WITHOUT ANY WARRANTY; without even the implied warranty of
15181254a7SmrgMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16181254a7SmrgGNU General Public License for more details.
17181254a7Smrg
18181254a7SmrgUnder Section 7 of GPL version 3, you are granted additional
19181254a7Smrgpermissions described in the GCC Runtime Library Exception, version
20181254a7Smrg3.1, as published by the Free Software Foundation.
21181254a7Smrg
22181254a7SmrgYou should have received a copy of the GNU General Public License and
23181254a7Smrga copy of the GCC Runtime Library Exception along with this program;
24181254a7Smrgsee the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
25181254a7Smrg<http://www.gnu.org/licenses/>.  */
26181254a7Smrg
27181254a7Smrg#include "config.h"
28181254a7Smrg
29181254a7Smrgtypedef enum
30181254a7Smrg{ S_NONE, S_MINUS, S_PLUS }
31181254a7Smrgsign_t;
32181254a7Smrg
33181254a7Smrg/* Given a flag that indicates if a value is negative or not, return a
34181254a7Smrg   sign_t that gives the sign that we need to produce.  */
35181254a7Smrg
36181254a7Smrgstatic sign_t
37181254a7Smrgcalculate_sign (st_parameter_dt *dtp, int negative_flag)
38181254a7Smrg{
39181254a7Smrg  sign_t s = S_NONE;
40181254a7Smrg
41181254a7Smrg  if (negative_flag)
42181254a7Smrg    s = S_MINUS;
43181254a7Smrg  else
44181254a7Smrg    switch (dtp->u.p.sign_status)
45181254a7Smrg      {
46181254a7Smrg      case SIGN_SP:	/* Show sign. */
47181254a7Smrg	s = S_PLUS;
48181254a7Smrg	break;
49181254a7Smrg      case SIGN_SS:	/* Suppress sign. */
50181254a7Smrg	s = S_NONE;
51181254a7Smrg	break;
52181254a7Smrg      case SIGN_S:	/* Processor defined. */
53181254a7Smrg      case SIGN_UNSPECIFIED:
54181254a7Smrg	s = options.optional_plus ? S_PLUS : S_NONE;
55181254a7Smrg	break;
56181254a7Smrg      }
57181254a7Smrg
58181254a7Smrg  return s;
59181254a7Smrg}
60181254a7Smrg
61181254a7Smrg
62181254a7Smrg/* Determine the precision except for EN format. For G format,
63181254a7Smrg   determines an upper bound to be used for sizing the buffer. */
64181254a7Smrg
65181254a7Smrgstatic int
66181254a7Smrgdetermine_precision (st_parameter_dt * dtp, const fnode * f, int len)
67181254a7Smrg{
68181254a7Smrg  int precision = f->u.real.d;
69181254a7Smrg
70181254a7Smrg  switch (f->format)
71181254a7Smrg    {
72181254a7Smrg    case FMT_F:
73181254a7Smrg    case FMT_G:
74181254a7Smrg      precision += dtp->u.p.scale_factor;
75181254a7Smrg      break;
76181254a7Smrg    case FMT_ES:
77181254a7Smrg      /* Scale factor has no effect on output.  */
78181254a7Smrg      break;
79181254a7Smrg    case FMT_E:
80181254a7Smrg    case FMT_D:
81181254a7Smrg      /* See F2008 10.7.2.3.3.6 */
82181254a7Smrg      if (dtp->u.p.scale_factor <= 0)
83181254a7Smrg	precision += dtp->u.p.scale_factor - 1;
84181254a7Smrg      break;
85181254a7Smrg    default:
86181254a7Smrg      return -1;
87181254a7Smrg    }
88181254a7Smrg
89181254a7Smrg  /* If the scale factor has a large negative value, we must do our
90181254a7Smrg     own rounding? Use ROUND='NEAREST', which should be what snprintf
91181254a7Smrg     is using as well.  */
92181254a7Smrg  if (precision < 0 &&
93181254a7Smrg      (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
94181254a7Smrg       || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
95181254a7Smrg    dtp->u.p.current_unit->round_status = ROUND_NEAREST;
96181254a7Smrg
97181254a7Smrg  /* Add extra guard digits up to at least full precision when we do
98181254a7Smrg     our own rounding.  */
99181254a7Smrg  if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
100181254a7Smrg      && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
101181254a7Smrg    {
102181254a7Smrg      precision += 2 * len + 4;
103181254a7Smrg      if (precision < 0)
104181254a7Smrg	precision = 0;
105181254a7Smrg    }
106181254a7Smrg
107181254a7Smrg  return precision;
108181254a7Smrg}
109181254a7Smrg
110181254a7Smrg
111181254a7Smrg/* Build a real number according to its format which is FMT_G free.  */
112181254a7Smrg
113181254a7Smrgstatic void
114181254a7Smrgbuild_float_string (st_parameter_dt *dtp, const fnode *f, char *buffer,
115181254a7Smrg		    size_t size, int nprinted, int precision, int sign_bit,
116fb8a8121Smrg		    bool zero_flag, int npad, int default_width, char *result,
117fb8a8121Smrg		    size_t *len)
118181254a7Smrg{
119181254a7Smrg  char *put;
120181254a7Smrg  char *digits;
121181254a7Smrg  int e, w, d, p, i;
122181254a7Smrg  char expchar, rchar;
123181254a7Smrg  format_token ft;
124181254a7Smrg  /* Number of digits before the decimal point.  */
125181254a7Smrg  int nbefore;
126181254a7Smrg  /* Number of zeros after the decimal point.  */
127181254a7Smrg  int nzero;
128181254a7Smrg  /* Number of digits after the decimal point.  */
129181254a7Smrg  int nafter;
130181254a7Smrg  int leadzero;
131181254a7Smrg  int nblanks;
132181254a7Smrg  int ndigits, edigits;
133181254a7Smrg  sign_t sign;
134181254a7Smrg
135181254a7Smrg  ft = f->format;
136fb8a8121Smrg  if (f->u.real.w == DEFAULT_WIDTH)
137fb8a8121Smrg    /* This codepath can only be reached with -fdec-format-defaults. */
138fb8a8121Smrg    {
139fb8a8121Smrg      w = default_width;
140fb8a8121Smrg      d = precision;
141fb8a8121Smrg    }
142fb8a8121Smrg  else
143fb8a8121Smrg    {
144181254a7Smrg      w = f->u.real.w;
145181254a7Smrg      d = f->u.real.d;
146fb8a8121Smrg    }
147181254a7Smrg  p = dtp->u.p.scale_factor;
148181254a7Smrg  *len = 0;
149181254a7Smrg
150181254a7Smrg  rchar = '5';
151181254a7Smrg
152181254a7Smrg  /* We should always know the field width and precision.  */
153181254a7Smrg  if (d < 0)
154181254a7Smrg    internal_error (&dtp->common, "Unspecified precision");
155181254a7Smrg
156181254a7Smrg  sign = calculate_sign (dtp, sign_bit);
157181254a7Smrg
158181254a7Smrg  /* Calculate total number of digits.  */
159181254a7Smrg  if (ft == FMT_F)
160181254a7Smrg    ndigits = nprinted - 2;
161181254a7Smrg  else
162181254a7Smrg    ndigits = precision + 1;
163181254a7Smrg
164181254a7Smrg  /* Read the exponent back in.  */
165181254a7Smrg  if (ft != FMT_F)
166181254a7Smrg    e = atoi (&buffer[ndigits + 3]) + 1;
167181254a7Smrg  else
168181254a7Smrg    e = 0;
169181254a7Smrg
170181254a7Smrg  /* Make sure zero comes out as 0.0e0.   */
171181254a7Smrg  if (zero_flag)
172181254a7Smrg    e = 0;
173181254a7Smrg
174181254a7Smrg  /* Normalize the fractional component.  */
175181254a7Smrg  if (ft != FMT_F)
176181254a7Smrg    {
177181254a7Smrg      buffer[2] = buffer[1];
178181254a7Smrg      digits = &buffer[2];
179181254a7Smrg    }
180181254a7Smrg  else
181181254a7Smrg    digits = &buffer[1];
182181254a7Smrg
183181254a7Smrg  /* Figure out where to place the decimal point.  */
184181254a7Smrg  switch (ft)
185181254a7Smrg    {
186181254a7Smrg    case FMT_F:
187181254a7Smrg      nbefore = ndigits - precision;
188181254a7Smrg      if ((w > 0) && (nbefore > (int) size))
189181254a7Smrg        {
190181254a7Smrg	  *len = w;
191181254a7Smrg	  star_fill (result, w);
192181254a7Smrg	  result[w] = '\0';
193181254a7Smrg	  return;
194181254a7Smrg	}
195181254a7Smrg      /* Make sure the decimal point is a '.'; depending on the
196181254a7Smrg	 locale, this might not be the case otherwise.  */
197181254a7Smrg      digits[nbefore] = '.';
198181254a7Smrg      if (p != 0)
199181254a7Smrg	{
200181254a7Smrg	  if (p > 0)
201181254a7Smrg	    {
202181254a7Smrg	      memmove (digits + nbefore, digits + nbefore + 1, p);
203181254a7Smrg	      digits[nbefore + p] = '.';
204181254a7Smrg	      nbefore += p;
205181254a7Smrg	      nafter = d;
206181254a7Smrg	      nzero = 0;
207181254a7Smrg	    }
208181254a7Smrg	  else /* p < 0  */
209181254a7Smrg	    {
210181254a7Smrg	      if (nbefore + p >= 0)
211181254a7Smrg		{
212181254a7Smrg		  nzero = 0;
213181254a7Smrg		  memmove (digits + nbefore + p + 1, digits + nbefore + p, -p);
214181254a7Smrg		  nbefore += p;
215181254a7Smrg		  digits[nbefore] = '.';
216181254a7Smrg		  nafter = d;
217181254a7Smrg		}
218181254a7Smrg	      else
219181254a7Smrg		{
220181254a7Smrg		  nzero = -(nbefore + p);
221181254a7Smrg		  memmove (digits + 1, digits, nbefore);
222181254a7Smrg		  nafter = d - nzero;
223181254a7Smrg		  if (nafter == 0 && d > 0)
224181254a7Smrg		    {
225181254a7Smrg		      /* This is needed to get the correct rounding. */
226181254a7Smrg		      memmove (digits + 1, digits, ndigits - 1);
227181254a7Smrg		      digits[1] = '0';
228181254a7Smrg		      nafter = 1;
229181254a7Smrg		      nzero = d - 1;
230181254a7Smrg		    }
231181254a7Smrg		  else if (nafter < 0)
232181254a7Smrg		    {
233181254a7Smrg		      /* Reset digits to 0 in order to get correct rounding
234181254a7Smrg			 towards infinity. */
235181254a7Smrg		      for (i = 0; i < ndigits; i++)
236181254a7Smrg			digits[i] = '0';
237181254a7Smrg		      digits[ndigits - 1] = '1';
238181254a7Smrg		      nafter = d;
239181254a7Smrg		      nzero = 0;
240181254a7Smrg		    }
241181254a7Smrg		  nbefore = 0;
242181254a7Smrg		}
243181254a7Smrg	    }
244181254a7Smrg	}
245181254a7Smrg      else
246181254a7Smrg	{
247181254a7Smrg	  nzero = 0;
248181254a7Smrg	  nafter = d;
249181254a7Smrg	}
250181254a7Smrg
251181254a7Smrg      while (digits[0] == '0' && nbefore > 0)
252181254a7Smrg	{
253181254a7Smrg	  digits++;
254181254a7Smrg	  nbefore--;
255181254a7Smrg	  ndigits--;
256181254a7Smrg	}
257181254a7Smrg
258181254a7Smrg      expchar = 0;
259181254a7Smrg      /* If we need to do rounding ourselves, get rid of the dot by
260181254a7Smrg	 moving the fractional part.  */
261181254a7Smrg      if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
262181254a7Smrg	  && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
263181254a7Smrg	memmove (digits + nbefore, digits + nbefore + 1, ndigits - nbefore);
264181254a7Smrg      break;
265181254a7Smrg
266181254a7Smrg    case FMT_E:
267181254a7Smrg    case FMT_D:
268181254a7Smrg      i = dtp->u.p.scale_factor;
269fb8a8121Smrg      if (d < 0 && p == 0)
270181254a7Smrg	{
271181254a7Smrg	  generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
272181254a7Smrg			  "greater than zero in format specifier 'E' or 'D'");
273181254a7Smrg	  return;
274181254a7Smrg	}
275181254a7Smrg      if (p <= -d || p >= d + 2)
276181254a7Smrg	{
277181254a7Smrg	  generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
278181254a7Smrg			  "out of range in format specifier 'E' or 'D'");
279181254a7Smrg	  return;
280181254a7Smrg	}
281181254a7Smrg
282181254a7Smrg      if (!zero_flag)
283181254a7Smrg	e -= p;
284181254a7Smrg      if (p < 0)
285181254a7Smrg	{
286181254a7Smrg	  nbefore = 0;
287181254a7Smrg	  nzero = -p;
288181254a7Smrg	  nafter = d + p;
289181254a7Smrg	}
290181254a7Smrg      else if (p > 0)
291181254a7Smrg	{
292181254a7Smrg	  nbefore = p;
293181254a7Smrg	  nzero = 0;
294181254a7Smrg	  nafter = (d - p) + 1;
295181254a7Smrg	}
296181254a7Smrg      else /* p == 0 */
297181254a7Smrg	{
298181254a7Smrg	  nbefore = 0;
299181254a7Smrg	  nzero = 0;
300181254a7Smrg	  nafter = d;
301181254a7Smrg	}
302181254a7Smrg
303181254a7Smrg      if (ft == FMT_E)
304181254a7Smrg	expchar = 'E';
305181254a7Smrg      else
306181254a7Smrg	expchar = 'D';
307181254a7Smrg      break;
308181254a7Smrg
309181254a7Smrg    case FMT_EN:
310181254a7Smrg      /* The exponent must be a multiple of three, with 1-3 digits before
311181254a7Smrg	 the decimal point.  */
312181254a7Smrg      if (!zero_flag)
313181254a7Smrg        e--;
314181254a7Smrg      if (e >= 0)
315181254a7Smrg	nbefore = e % 3;
316181254a7Smrg      else
317181254a7Smrg	{
318181254a7Smrg	  nbefore = (-e) % 3;
319181254a7Smrg	  if (nbefore != 0)
320181254a7Smrg	    nbefore = 3 - nbefore;
321181254a7Smrg	}
322181254a7Smrg      e -= nbefore;
323181254a7Smrg      nbefore++;
324181254a7Smrg      nzero = 0;
325181254a7Smrg      nafter = d;
326181254a7Smrg      expchar = 'E';
327181254a7Smrg      break;
328181254a7Smrg
329181254a7Smrg    case FMT_ES:
330181254a7Smrg      if (!zero_flag)
331181254a7Smrg        e--;
332181254a7Smrg      nbefore = 1;
333181254a7Smrg      nzero = 0;
334181254a7Smrg      nafter = d;
335181254a7Smrg      expchar = 'E';
336181254a7Smrg      break;
337181254a7Smrg
338181254a7Smrg    default:
339181254a7Smrg      /* Should never happen.  */
340181254a7Smrg      internal_error (&dtp->common, "Unexpected format token");
341181254a7Smrg    }
342181254a7Smrg
343181254a7Smrg  if (zero_flag)
344181254a7Smrg    goto skip;
345181254a7Smrg
346181254a7Smrg  /* Round the value.  The value being rounded is an unsigned magnitude.  */
347181254a7Smrg  switch (dtp->u.p.current_unit->round_status)
348181254a7Smrg    {
349181254a7Smrg      /* For processor defined and unspecified rounding we use
350181254a7Smrg	 snprintf to print the exact number of digits needed, and thus
351181254a7Smrg	 let snprintf handle the rounding.  On system claiming support
352181254a7Smrg	 for IEEE 754, this ought to be round to nearest, ties to
353181254a7Smrg	 even, corresponding to the Fortran ROUND='NEAREST'.  */
354181254a7Smrg      case ROUND_PROCDEFINED:
355181254a7Smrg      case ROUND_UNSPECIFIED:
356181254a7Smrg      case ROUND_ZERO: /* Do nothing and truncation occurs.  */
357181254a7Smrg	goto skip;
358181254a7Smrg      case ROUND_UP:
359181254a7Smrg	if (sign_bit)
360181254a7Smrg	  goto skip;
361181254a7Smrg	goto updown;
362181254a7Smrg      case ROUND_DOWN:
363181254a7Smrg	if (!sign_bit)
364181254a7Smrg	  goto skip;
365181254a7Smrg	goto updown;
366181254a7Smrg      case ROUND_NEAREST:
367181254a7Smrg	/* Round compatible unless there is a tie. A tie is a 5 with
368181254a7Smrg	   all trailing zero's.  */
369181254a7Smrg	i = nafter + nbefore;
370181254a7Smrg	if (digits[i] == '5')
371181254a7Smrg	  {
372181254a7Smrg	    for(i++ ; i < ndigits; i++)
373181254a7Smrg	      {
374181254a7Smrg		if (digits[i] != '0')
375181254a7Smrg		  goto do_rnd;
376181254a7Smrg	      }
377181254a7Smrg	    /* It is a tie so round to even.  */
378181254a7Smrg	    switch (digits[nafter + nbefore - 1])
379181254a7Smrg	      {
380181254a7Smrg		case '1':
381181254a7Smrg		case '3':
382181254a7Smrg		case '5':
383181254a7Smrg		case '7':
384181254a7Smrg		case '9':
385181254a7Smrg		  /* If odd, round away from zero to even.  */
386181254a7Smrg		  break;
387181254a7Smrg		default:
388181254a7Smrg		  /* If even, skip rounding, truncate to even.  */
389181254a7Smrg		  goto skip;
390181254a7Smrg	      }
391181254a7Smrg	  }
392181254a7Smrg	/* Fall through.  */
393181254a7Smrg	/* The ROUND_COMPATIBLE is rounding away from zero when there is a tie.  */
394181254a7Smrg      case ROUND_COMPATIBLE:
395181254a7Smrg	rchar = '5';
396181254a7Smrg	goto do_rnd;
397181254a7Smrg    }
398181254a7Smrg
399181254a7Smrg  updown:
400181254a7Smrg
401181254a7Smrg  rchar = '0';
402fb8a8121Smrg  /* Do not reset nbefore for FMT_F and FMT_EN.  */
403fb8a8121Smrg  if (ft != FMT_F && ft !=FMT_EN && w > 0 && d == 0 && p == 0)
404181254a7Smrg    nbefore = 1;
405181254a7Smrg  /* Scan for trailing zeros to see if we really need to round it.  */
406181254a7Smrg  for(i = nbefore + nafter; i < ndigits; i++)
407181254a7Smrg    {
408181254a7Smrg      if (digits[i] != '0')
409181254a7Smrg	goto do_rnd;
410181254a7Smrg    }
411181254a7Smrg  goto skip;
412181254a7Smrg
413181254a7Smrg  do_rnd:
414181254a7Smrg
415181254a7Smrg  if (nbefore + nafter == 0)
416181254a7Smrg    /* Handle the case Fw.0 and value < 1.0 */
417181254a7Smrg    {
418181254a7Smrg      ndigits = 0;
419181254a7Smrg      if (digits[0] >= rchar)
420181254a7Smrg	{
421181254a7Smrg	  /* We rounded to zero but shouldn't have */
422181254a7Smrg	  nbefore = 1;
423181254a7Smrg	  digits--;
424181254a7Smrg	  digits[0] = '1';
425181254a7Smrg	  ndigits = 1;
426181254a7Smrg	}
427181254a7Smrg    }
428181254a7Smrg  else if (nbefore + nafter < ndigits)
429181254a7Smrg    {
430181254a7Smrg      i = ndigits = nbefore + nafter;
431181254a7Smrg      if (digits[i] >= rchar)
432181254a7Smrg	{
433181254a7Smrg	  /* Propagate the carry.  */
434181254a7Smrg	  for (i--; i >= 0; i--)
435181254a7Smrg	    {
436181254a7Smrg	      if (digits[i] != '9')
437181254a7Smrg		{
438181254a7Smrg		  digits[i]++;
439181254a7Smrg		  break;
440181254a7Smrg		}
441181254a7Smrg	      digits[i] = '0';
442181254a7Smrg	    }
443181254a7Smrg
444181254a7Smrg	  if (i < 0)
445181254a7Smrg	    {
446181254a7Smrg	      /* The carry overflowed.  Fortunately we have some spare
447181254a7Smrg	         space at the start of the buffer.  We may discard some
448181254a7Smrg	         digits, but this is ok because we already know they are
449181254a7Smrg	         zero.  */
450181254a7Smrg	      digits--;
451181254a7Smrg	      digits[0] = '1';
452181254a7Smrg	      if (ft == FMT_F)
453181254a7Smrg		{
454181254a7Smrg		  if (nzero > 0)
455181254a7Smrg		    {
456181254a7Smrg		      nzero--;
457181254a7Smrg		      nafter++;
458181254a7Smrg		    }
459181254a7Smrg		  else
460181254a7Smrg		    nbefore++;
461181254a7Smrg		}
462181254a7Smrg	      else if (ft == FMT_EN)
463181254a7Smrg		{
464181254a7Smrg		  nbefore++;
465181254a7Smrg		  if (nbefore == 4)
466181254a7Smrg		    {
467181254a7Smrg		      nbefore = 1;
468181254a7Smrg		      e += 3;
469181254a7Smrg		    }
470181254a7Smrg		}
471181254a7Smrg	      else
472181254a7Smrg		e++;
473181254a7Smrg	    }
474181254a7Smrg	}
475181254a7Smrg    }
476181254a7Smrg
477181254a7Smrg  skip:
478181254a7Smrg
479181254a7Smrg  /* Calculate the format of the exponent field.  */
480181254a7Smrg  if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
481181254a7Smrg    {
482181254a7Smrg      edigits = 1;
483181254a7Smrg      for (i = abs (e); i >= 10; i /= 10)
484181254a7Smrg	edigits++;
485181254a7Smrg
486181254a7Smrg      if (f->u.real.e < 0)
487181254a7Smrg	{
488181254a7Smrg	  /* Width not specified.  Must be no more than 3 digits.  */
489181254a7Smrg	  if (e > 999 || e < -999)
490181254a7Smrg	    edigits = -1;
491181254a7Smrg	  else
492181254a7Smrg	    {
493181254a7Smrg	      edigits = 4;
494181254a7Smrg	      if (e > 99 || e < -99)
495181254a7Smrg		expchar = ' ';
496181254a7Smrg	    }
497181254a7Smrg	}
498fb8a8121Smrg      else if (f->u.real.e == 0)
499fb8a8121Smrg	{
500fb8a8121Smrg	  /* Zero width specified, no leading zeros in exponent  */
501fb8a8121Smrg	  if (e > 999 || e < -999)
502fb8a8121Smrg	    edigits = 6;
503fb8a8121Smrg	  else if (e > 99 || e < -99)
504fb8a8121Smrg	    edigits = 5;
505fb8a8121Smrg	  else if (e > 9 || e < -9)
506fb8a8121Smrg	    edigits = 4;
507fb8a8121Smrg	  else
508fb8a8121Smrg	    edigits = 3;
509fb8a8121Smrg	}
510181254a7Smrg      else
511181254a7Smrg	{
512181254a7Smrg	  /* Exponent width specified, check it is wide enough.  */
513181254a7Smrg	  if (edigits > f->u.real.e)
514181254a7Smrg	    edigits = -1;
515181254a7Smrg	  else
516181254a7Smrg	    edigits = f->u.real.e + 2;
517181254a7Smrg	}
518181254a7Smrg    }
519181254a7Smrg  else
520181254a7Smrg    edigits = 0;
521181254a7Smrg
522181254a7Smrg  /* Scan the digits string and count the number of zeros.  If we make it
523181254a7Smrg     all the way through the loop, we know the value is zero after the
524181254a7Smrg     rounding completed above.  */
525181254a7Smrg  int hasdot = 0;
526181254a7Smrg  for (i = 0; i < ndigits + hasdot; i++)
527181254a7Smrg    {
528181254a7Smrg      if (digits[i] == '.')
529181254a7Smrg	hasdot = 1;
530181254a7Smrg      else if (digits[i] != '0')
531181254a7Smrg	break;
532181254a7Smrg    }
533181254a7Smrg
534181254a7Smrg  /* To format properly, we need to know if the rounded result is zero and if
535181254a7Smrg     so, we set the zero_flag which may have been already set for
536181254a7Smrg     actual zero.  */
537181254a7Smrg  if (i == ndigits + hasdot)
538181254a7Smrg    {
539181254a7Smrg      zero_flag = true;
540181254a7Smrg      /* The output is zero, so set the sign according to the sign bit unless
541181254a7Smrg	 -fno-sign-zero was specified.  */
542181254a7Smrg      if (compile_options.sign_zero == 1)
543181254a7Smrg        sign = calculate_sign (dtp, sign_bit);
544181254a7Smrg      else
545181254a7Smrg	sign = calculate_sign (dtp, 0);
546181254a7Smrg    }
547181254a7Smrg
548181254a7Smrg  /* Pick a field size if none was specified, taking into account small
549181254a7Smrg     values that may have been rounded to zero.  */
550181254a7Smrg  if (w <= 0)
551181254a7Smrg    {
552181254a7Smrg      if (zero_flag)
553181254a7Smrg	w = d + (sign != S_NONE ? 2 : 1) + (d == 0 ? 1 : 0);
554181254a7Smrg      else
555181254a7Smrg	{
556181254a7Smrg	  w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1);
557181254a7Smrg	  w = w == 1 ? 2 : w;
558181254a7Smrg	}
559181254a7Smrg    }
560181254a7Smrg
561181254a7Smrg  /* Work out how much padding is needed.  */
562181254a7Smrg  nblanks = w - (nbefore + nzero + nafter + edigits + 1);
563181254a7Smrg  if (sign != S_NONE)
564181254a7Smrg    nblanks--;
565181254a7Smrg
566181254a7Smrg  /* See if we have space for a zero before the decimal point.  */
567181254a7Smrg  if (nbefore == 0 && nblanks > 0)
568181254a7Smrg    {
569181254a7Smrg      leadzero = 1;
570181254a7Smrg      nblanks--;
571181254a7Smrg    }
572181254a7Smrg  else
573181254a7Smrg    leadzero = 0;
574181254a7Smrg
575181254a7Smrg  if (dtp->u.p.g0_no_blanks)
576181254a7Smrg    {
577181254a7Smrg      w -= nblanks;
578181254a7Smrg      nblanks = 0;
579181254a7Smrg    }
580181254a7Smrg
581181254a7Smrg  /* Create the final float string.  */
582181254a7Smrg  *len = w + npad;
583181254a7Smrg  put = result;
584181254a7Smrg
585181254a7Smrg  /* Check the value fits in the specified field width.  */
586181254a7Smrg  if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE))
587181254a7Smrg    {
588181254a7Smrg      star_fill (put, *len);
589181254a7Smrg      return;
590181254a7Smrg    }
591181254a7Smrg
592181254a7Smrg  /* Pad to full field width.  */
593181254a7Smrg  if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
594181254a7Smrg    {
595181254a7Smrg      memset (put, ' ', nblanks);
596181254a7Smrg      put += nblanks;
597181254a7Smrg    }
598181254a7Smrg
599181254a7Smrg  /* Set the initial sign (if any).  */
600181254a7Smrg  if (sign == S_PLUS)
601181254a7Smrg    *(put++) = '+';
602181254a7Smrg  else if (sign == S_MINUS)
603181254a7Smrg    *(put++) = '-';
604181254a7Smrg
605181254a7Smrg  /* Set an optional leading zero.  */
606181254a7Smrg  if (leadzero)
607181254a7Smrg    *(put++) = '0';
608181254a7Smrg
609181254a7Smrg  /* Set the part before the decimal point, padding with zeros.  */
610181254a7Smrg  if (nbefore > 0)
611181254a7Smrg    {
612181254a7Smrg      if (nbefore > ndigits)
613181254a7Smrg	{
614181254a7Smrg	  i = ndigits;
615181254a7Smrg	  memcpy (put, digits, i);
616181254a7Smrg	  ndigits = 0;
617181254a7Smrg	  while (i < nbefore)
618181254a7Smrg	    put[i++] = '0';
619181254a7Smrg	}
620181254a7Smrg      else
621181254a7Smrg	{
622181254a7Smrg	  i = nbefore;
623181254a7Smrg	  memcpy (put, digits, i);
624181254a7Smrg	  ndigits -= i;
625181254a7Smrg	}
626181254a7Smrg
627181254a7Smrg      digits += i;
628181254a7Smrg      put += nbefore;
629181254a7Smrg    }
630181254a7Smrg
631181254a7Smrg  /* Set the decimal point.  */
632181254a7Smrg  *(put++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
633181254a7Smrg  if (ft == FMT_F
634181254a7Smrg	  && (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
635181254a7Smrg	      || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
636181254a7Smrg    digits++;
637181254a7Smrg
638181254a7Smrg  /* Set leading zeros after the decimal point.  */
639181254a7Smrg  if (nzero > 0)
640181254a7Smrg    {
641181254a7Smrg      for (i = 0; i < nzero; i++)
642181254a7Smrg	*(put++) = '0';
643181254a7Smrg    }
644181254a7Smrg
645181254a7Smrg  /* Set digits after the decimal point, padding with zeros.  */
646181254a7Smrg  if (ndigits >= 0 && nafter > 0)
647181254a7Smrg    {
648181254a7Smrg      if (nafter > ndigits)
649181254a7Smrg	i = ndigits;
650181254a7Smrg      else
651181254a7Smrg	i = nafter;
652181254a7Smrg
653181254a7Smrg      if (i > 0)
654181254a7Smrg	memcpy (put, digits, i);
655181254a7Smrg      while (i < nafter)
656181254a7Smrg	put[i++] = '0';
657181254a7Smrg
658181254a7Smrg      digits += i;
659181254a7Smrg      ndigits -= i;
660181254a7Smrg      put += nafter;
661181254a7Smrg    }
662181254a7Smrg
663181254a7Smrg  /* Set the exponent.  */
664181254a7Smrg  if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
665181254a7Smrg    {
666181254a7Smrg      if (expchar != ' ')
667181254a7Smrg	{
668181254a7Smrg	  *(put++) = expchar;
669181254a7Smrg	  edigits--;
670181254a7Smrg	}
671181254a7Smrg      snprintf (buffer, size, "%+0*d", edigits, e);
672181254a7Smrg      memcpy (put, buffer, edigits);
673181254a7Smrg      put += edigits;
674181254a7Smrg    }
675181254a7Smrg
676181254a7Smrg  if (dtp->u.p.no_leading_blank)
677181254a7Smrg    {
678181254a7Smrg      memset (put , ' ' , nblanks);
679181254a7Smrg      dtp->u.p.no_leading_blank = 0;
680181254a7Smrg      put += nblanks;
681181254a7Smrg    }
682181254a7Smrg
683181254a7Smrg  if (npad > 0 && !dtp->u.p.g0_no_blanks)
684181254a7Smrg    {
685181254a7Smrg      memset (put , ' ' , npad);
686181254a7Smrg      put += npad;
687181254a7Smrg    }
688181254a7Smrg
689181254a7Smrg  /* NULL terminate the string.  */
690181254a7Smrg  *put = '\0';
691181254a7Smrg
692181254a7Smrg  return;
693181254a7Smrg}
694181254a7Smrg
695181254a7Smrg
696181254a7Smrg/* Write "Infinite" or "Nan" as appropriate for the given format.  */
697181254a7Smrg
698181254a7Smrgstatic void
699181254a7Smrgbuild_infnan_string (st_parameter_dt *dtp, const fnode *f, int isnan_flag,
700181254a7Smrg		    int sign_bit, char *p, size_t *len)
701181254a7Smrg{
702181254a7Smrg  char fin;
703181254a7Smrg  int nb = 0;
704181254a7Smrg  sign_t sign;
705181254a7Smrg  int mark;
706181254a7Smrg
707181254a7Smrg  if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
708181254a7Smrg    {
709181254a7Smrg      sign = calculate_sign (dtp, sign_bit);
710181254a7Smrg      mark = (sign == S_PLUS || sign == S_MINUS) ? 8 : 7;
711181254a7Smrg
712181254a7Smrg      nb =  f->u.real.w;
713181254a7Smrg      *len = nb;
714181254a7Smrg
715181254a7Smrg      /* If the field width is zero, the processor must select a width
716181254a7Smrg	 not zero.  4 is chosen to allow output of '-Inf' or '+Inf' */
717181254a7Smrg
718181254a7Smrg      if ((nb == 0) || dtp->u.p.g0_no_blanks)
719181254a7Smrg	{
720181254a7Smrg	  if (isnan_flag)
721181254a7Smrg	    nb = 3;
722181254a7Smrg	  else
723181254a7Smrg	    nb = (sign == S_PLUS || sign == S_MINUS) ? 4 : 3;
724181254a7Smrg	  *len = nb;
725181254a7Smrg	}
726181254a7Smrg
727181254a7Smrg      p[*len] = '\0';
728181254a7Smrg      if (nb < 3)
729181254a7Smrg	{
730181254a7Smrg	  memset (p, '*', nb);
731181254a7Smrg	  return;
732181254a7Smrg	}
733181254a7Smrg
734181254a7Smrg      memset(p, ' ', nb);
735181254a7Smrg
736181254a7Smrg      if (!isnan_flag)
737181254a7Smrg	{
738181254a7Smrg	  if (sign_bit)
739181254a7Smrg	    {
740181254a7Smrg	      /* If the sign is negative and the width is 3, there is
741181254a7Smrg		 insufficient room to output '-Inf', so output asterisks */
742181254a7Smrg	      if (nb == 3)
743181254a7Smrg		{
744181254a7Smrg		  memset (p, '*', nb);
745181254a7Smrg		  return;
746181254a7Smrg		}
747181254a7Smrg	      /* The negative sign is mandatory */
748181254a7Smrg	      fin = '-';
749181254a7Smrg	    }
750181254a7Smrg	  else
751181254a7Smrg	    /* The positive sign is optional, but we output it for
752181254a7Smrg	       consistency */
753181254a7Smrg	    fin = '+';
754181254a7Smrg
755181254a7Smrg	  if (nb > mark)
756181254a7Smrg	    /* We have room, so output 'Infinity' */
757181254a7Smrg	    memcpy(p + nb - 8, "Infinity", 8);
758181254a7Smrg	  else
759181254a7Smrg	    /* For the case of width equals 8, there is not enough room
760181254a7Smrg	       for the sign and 'Infinity' so we go with 'Inf' */
761181254a7Smrg	    memcpy(p + nb - 3, "Inf", 3);
762181254a7Smrg
763181254a7Smrg	  if (sign == S_PLUS || sign == S_MINUS)
764181254a7Smrg	    {
765181254a7Smrg	      if (nb < 9 && nb > 3)
766181254a7Smrg		p[nb - 4] = fin;  /* Put the sign in front of Inf */
767181254a7Smrg	      else if (nb > 8)
768181254a7Smrg		p[nb - 9] = fin;  /* Put the sign in front of Infinity */
769181254a7Smrg	    }
770181254a7Smrg	}
771181254a7Smrg      else
772181254a7Smrg	memcpy(p + nb - 3, "NaN", 3);
773181254a7Smrg    }
774181254a7Smrg}
775181254a7Smrg
776181254a7Smrg
777181254a7Smrg/* Returns the value of 10**d.  */
778181254a7Smrg
779181254a7Smrg#define CALCULATE_EXP(x) \
780181254a7Smrgstatic GFC_REAL_ ## x \
781181254a7Smrgcalculate_exp_ ## x  (int d)\
782181254a7Smrg{\
783181254a7Smrg  int i;\
784181254a7Smrg  GFC_REAL_ ## x r = 1.0;\
785181254a7Smrg  for (i = 0; i< (d >= 0 ? d : -d); i++)\
786181254a7Smrg    r *= 10;\
787181254a7Smrg  r = (d >= 0) ? r : 1.0 / r;\
788181254a7Smrg  return r;\
789181254a7Smrg}
790181254a7Smrg
791181254a7SmrgCALCULATE_EXP(4)
792181254a7Smrg
793181254a7SmrgCALCULATE_EXP(8)
794181254a7Smrg
795181254a7Smrg#ifdef HAVE_GFC_REAL_10
796181254a7SmrgCALCULATE_EXP(10)
797181254a7Smrg#endif
798181254a7Smrg
799181254a7Smrg#ifdef HAVE_GFC_REAL_16
800181254a7SmrgCALCULATE_EXP(16)
801181254a7Smrg#endif
802*b1e83836Smrg
803*b1e83836Smrg#ifdef HAVE_GFC_REAL_17
804*b1e83836SmrgCALCULATE_EXP(17)
805*b1e83836Smrg#endif
806181254a7Smrg#undef CALCULATE_EXP
807181254a7Smrg
808181254a7Smrg
809181254a7Smrg/* Define macros to build code for format_float.  */
810181254a7Smrg
811181254a7Smrg  /* Note: Before output_float is called, snprintf is used to print to buffer the
812181254a7Smrg     number in the format +D.DDDDe+ddd.
813181254a7Smrg
814181254a7Smrg     #   The result will always contain a decimal point, even if no
815181254a7Smrg	 digits follow it
816181254a7Smrg
817181254a7Smrg     -   The converted value is to be left adjusted on the field boundary
818181254a7Smrg
819181254a7Smrg     +   A sign (+ or -) always be placed before a number
820181254a7Smrg
821181254a7Smrg     *   prec is used as the precision
822181254a7Smrg
823181254a7Smrg     e format: [-]d.ddde±dd where there is one digit before the
824181254a7Smrg       decimal-point character and the number of digits after it is
825181254a7Smrg       equal to the precision. The exponent always contains at least two
826181254a7Smrg       digits; if the value is zero, the exponent is 00.  */
827181254a7Smrg
828181254a7Smrg
829181254a7Smrg#define TOKENPASTE(x, y) TOKENPASTE2(x, y)
830181254a7Smrg#define TOKENPASTE2(x, y) x ## y
831181254a7Smrg
832181254a7Smrg#define DTOA(suff,prec,val) TOKENPASTE(DTOA2,suff)(prec,val)
833181254a7Smrg
834181254a7Smrg#define DTOA2(prec,val) \
835181254a7Smrgsnprintf (buffer, size, "%+-#.*e", (prec), (val))
836181254a7Smrg
837181254a7Smrg#define DTOA2L(prec,val) \
838181254a7Smrgsnprintf (buffer, size, "%+-#.*Le", (prec), (val))
839181254a7Smrg
840181254a7Smrg
841*b1e83836Smrg#if defined(HAVE_GFC_REAL_17)
842*b1e83836Smrg# if defined(POWER_IEEE128)
843*b1e83836Smrg#  define DTOA2Q(prec,val) \
844*b1e83836Smrg__snprintfieee128 (buffer, size, "%+-#.*Le", (prec), (val))
845*b1e83836Smrg# else
846*b1e83836Smrg#  define DTOA2Q(prec,val) \
847*b1e83836Smrgquadmath_snprintf (buffer, size, "%+-#.*Qe", (prec), (val))
848*b1e83836Smrg# endif
849*b1e83836Smrg#elif defined(GFC_REAL_16_IS_FLOAT128)
850181254a7Smrg# define DTOA2Q(prec,val) \
851181254a7Smrgquadmath_snprintf (buffer, size, "%+-#.*Qe", (prec), (val))
852181254a7Smrg#endif
853181254a7Smrg
854181254a7Smrg#define FDTOA(suff,prec,val) TOKENPASTE(FDTOA2,suff)(prec,val)
855181254a7Smrg
856181254a7Smrg/* For F format, we print to the buffer with f format.  */
857181254a7Smrg#define FDTOA2(prec,val) \
858181254a7Smrgsnprintf (buffer, size, "%+-#.*f", (prec), (val))
859181254a7Smrg
860181254a7Smrg#define FDTOA2L(prec,val) \
861181254a7Smrgsnprintf (buffer, size, "%+-#.*Lf", (prec), (val))
862181254a7Smrg
863181254a7Smrg
864*b1e83836Smrg#if defined(HAVE_GFC_REAL_17)
865*b1e83836Smrg# if defined(POWER_IEEE128)
866181254a7Smrg#  define FDTOA2Q(prec,val) \
867*b1e83836Smrg__snprintfieee128 (buffer, size, "%+-#.*Lf", (prec), (val))
868*b1e83836Smrg# else
869*b1e83836Smrg# define FDTOA2Q(prec,val) \
870*b1e83836Smrgquadmath_snprintf (buffer, size, "%+-#.*Qf", (prec), (val))
871*b1e83836Smrg# endif
872*b1e83836Smrg#elif defined(GFC_REAL_16_IS_FLOAT128)
873*b1e83836Smrg# define FDTOA2Q(prec,val) \
874*b1e83836Smrgquadmath_snprintf (buffer, size, "%+-#.*Qf", (prec), (val))
875181254a7Smrg#endif
876181254a7Smrg
877181254a7Smrg
878181254a7Smrg/* EN format is tricky since the number of significant digits depends
879181254a7Smrg   on the magnitude.  Solve it by first printing a temporary value and
880181254a7Smrg   figure out the number of significant digits from the printed
881181254a7Smrg   exponent.  Values y, 0.95*10.0**e <= y <10.0**e, are rounded to
882181254a7Smrg   10.0**e even when the final result will not be rounded to 10.0**e.
883181254a7Smrg   For these values the exponent returned by atoi has to be decremented
884181254a7Smrg   by one. The values y in the ranges
885181254a7Smrg       (1000.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*(n+1))
886181254a7Smrg        (100.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+2)
887181254a7Smrg         (10.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+1)
888181254a7Smrg   are correctly rounded respectively to 1.0...0*10.0*(3*(n+1)),
889181254a7Smrg   100.0...0*10.0*(3*n), and 10.0...0*10.0*(3*n), where 0...0
890181254a7Smrg   represents d zeroes, by the lines 279 to 297. */
891181254a7Smrg#define EN_PREC(x,y)\
892181254a7Smrg{\
893181254a7Smrg    volatile GFC_REAL_ ## x tmp, one = 1.0;\
894181254a7Smrg    tmp = * (GFC_REAL_ ## x *)source;\
895181254a7Smrg    if (isfinite (tmp))\
896181254a7Smrg      {\
897181254a7Smrg	nprinted = DTOA(y,0,tmp);\
898181254a7Smrg	int e = atoi (&buffer[4]);\
899181254a7Smrg	if (buffer[1] == '1')\
900181254a7Smrg	  {\
901181254a7Smrg	    tmp = (calculate_exp_ ## x (-e)) * tmp;\
902181254a7Smrg	    tmp = one - (tmp < 0 ? -tmp : tmp);\
903181254a7Smrg	    if (tmp > 0)\
904181254a7Smrg	      e = e - 1;\
905181254a7Smrg	  }\
906181254a7Smrg	nbefore = e%3;\
907181254a7Smrg	if (nbefore < 0)\
908181254a7Smrg	  nbefore = 3 + nbefore;\
909181254a7Smrg      }\
910181254a7Smrg    else\
911181254a7Smrg      nprinted = -1;\
912181254a7Smrg}\
913181254a7Smrg
914181254a7Smrgstatic int
915181254a7Smrgdetermine_en_precision (st_parameter_dt *dtp, const fnode *f,
916181254a7Smrg			const char *source, int len)
917181254a7Smrg{
918181254a7Smrg  int nprinted;
919181254a7Smrg  char buffer[10];
920181254a7Smrg  const size_t size = 10;
921181254a7Smrg  int nbefore; /* digits before decimal point - 1.  */
922181254a7Smrg
923181254a7Smrg  switch (len)
924181254a7Smrg    {
925181254a7Smrg    case 4:
926181254a7Smrg      EN_PREC(4,)
927181254a7Smrg      break;
928181254a7Smrg
929181254a7Smrg    case 8:
930181254a7Smrg      EN_PREC(8,)
931181254a7Smrg      break;
932181254a7Smrg
933181254a7Smrg#ifdef HAVE_GFC_REAL_10
934181254a7Smrg    case 10:
935181254a7Smrg      EN_PREC(10,L)
936181254a7Smrg      break;
937181254a7Smrg#endif
938181254a7Smrg#ifdef HAVE_GFC_REAL_16
939181254a7Smrg    case 16:
940181254a7Smrg# ifdef GFC_REAL_16_IS_FLOAT128
941181254a7Smrg      EN_PREC(16,Q)
942181254a7Smrg# else
943181254a7Smrg      EN_PREC(16,L)
944181254a7Smrg# endif
945181254a7Smrg      break;
946181254a7Smrg#endif
947*b1e83836Smrg#ifdef HAVE_GFC_REAL_17
948*b1e83836Smrg    case 17:
949*b1e83836Smrg      EN_PREC(17,Q)
950*b1e83836Smrg#endif
951*b1e83836Smrg      break;
952181254a7Smrg    default:
953181254a7Smrg      internal_error (NULL, "bad real kind");
954181254a7Smrg    }
955181254a7Smrg
956181254a7Smrg  if (nprinted == -1)
957181254a7Smrg    return -1;
958181254a7Smrg
959181254a7Smrg  int prec = f->u.real.d + nbefore;
960181254a7Smrg  if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
961181254a7Smrg      && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
962181254a7Smrg    prec += 2 * len + 4;
963181254a7Smrg  return prec;
964181254a7Smrg}
965181254a7Smrg
966181254a7Smrg
967181254a7Smrg/* Generate corresponding I/O format. and output.
968181254a7Smrg   The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
969181254a7Smrg   LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
970181254a7Smrg
971181254a7Smrg   Data Magnitude                              Equivalent Conversion
972181254a7Smrg   0< m < 0.1-0.5*10**(-d-1)                   Ew.d[Ee]
973181254a7Smrg   m = 0                                       F(w-n).(d-1), n' '
974181254a7Smrg   0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d)     F(w-n).d, n' '
975181254a7Smrg   1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1)      F(w-n).(d-1), n' '
976181254a7Smrg   10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2)  F(w-n).(d-2), n' '
977181254a7Smrg   ................                           ..........
978181254a7Smrg   10**(d-1)-0.5*10**(-1)<= m <10**d-0.5       F(w-n).0,n(' ')
979181254a7Smrg   m >= 10**d-0.5                              Ew.d[Ee]
980181254a7Smrg
981181254a7Smrg   notes: for Gw.d ,  n' ' means 4 blanks
982181254a7Smrg	  for Gw.dEe, n' ' means e+2 blanks
983181254a7Smrg	  for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
984181254a7Smrg	  the asm volatile is required for 32-bit x86 platforms.  */
985181254a7Smrg#define FORMAT_FLOAT(x,y)\
986181254a7Smrg{\
987181254a7Smrg  int npad = 0;\
988181254a7Smrg  GFC_REAL_ ## x m;\
989181254a7Smrg  m = * (GFC_REAL_ ## x *)source;\
990181254a7Smrg  sign_bit = signbit (m);\
991181254a7Smrg  if (!isfinite (m))\
992181254a7Smrg    { \
993181254a7Smrg      build_infnan_string (dtp, f, isnan (m), sign_bit, result, res_len);\
994181254a7Smrg      return;\
995181254a7Smrg    }\
996181254a7Smrg  m = sign_bit ? -m : m;\
997181254a7Smrg  zero_flag = (m == 0.0);\
998181254a7Smrg  if (f->format == FMT_G)\
999181254a7Smrg    {\
1000181254a7Smrg      int e = f->u.real.e;\
1001181254a7Smrg      int d = f->u.real.d;\
1002181254a7Smrg      int w = f->u.real.w;\
1003181254a7Smrg      fnode newf;\
1004181254a7Smrg      GFC_REAL_ ## x exp_d, r = 0.5, r_sc;\
1005181254a7Smrg      int low, high, mid;\
1006181254a7Smrg      int ubound, lbound;\
1007181254a7Smrg      int save_scale_factor;\
1008181254a7Smrg      volatile GFC_REAL_ ## x temp;\
1009181254a7Smrg      save_scale_factor = dtp->u.p.scale_factor;\
1010fb8a8121Smrg      if (w == DEFAULT_WIDTH)\
1011fb8a8121Smrg	{\
1012fb8a8121Smrg	  w = default_width;\
1013fb8a8121Smrg	  d = precision;\
1014fb8a8121Smrg	}\
1015fb8a8121Smrg      /* The switch between FMT_E and FMT_F is based on the absolute value.  \
1016fb8a8121Smrg         Set r=0 for rounding toward zero and r = 1 otherwise.  \
1017fb8a8121Smrg	 If (exp_d - m) == 1 there is no rounding needed.  */\
1018181254a7Smrg      switch (dtp->u.p.current_unit->round_status)\
1019181254a7Smrg	{\
1020181254a7Smrg	  case ROUND_ZERO:\
1021fb8a8121Smrg	    r = 0.0;\
1022181254a7Smrg	    break;\
1023181254a7Smrg	  case ROUND_UP:\
1024fb8a8121Smrg	    r = sign_bit ? 0.0 : 1.0;\
1025181254a7Smrg	    break;\
1026181254a7Smrg	  case ROUND_DOWN:\
1027fb8a8121Smrg	    r = sign_bit ? 1.0 : 0.0;\
1028181254a7Smrg	    break;\
1029181254a7Smrg	  default:\
1030181254a7Smrg	    break;\
1031181254a7Smrg	}\
1032181254a7Smrg      exp_d = calculate_exp_ ## x (d);\
1033181254a7Smrg      r_sc = (1 - r / exp_d);\
1034181254a7Smrg      temp = 0.1 * r_sc;\
1035fb8a8121Smrg      if ((m > 0.0 && ((m < temp) || (r < 1 && r >= (exp_d - m))\
1036fb8a8121Smrg				  || (r == 1 && 1 > (exp_d - m))))\
1037181254a7Smrg	  || ((m == 0.0) && !(compile_options.allow_std\
1038181254a7Smrg			      & (GFC_STD_F2003 | GFC_STD_F2008)))\
1039181254a7Smrg	  ||  d == 0)\
1040181254a7Smrg	{ \
1041181254a7Smrg	  newf.format = FMT_E;\
1042181254a7Smrg	  newf.u.real.w = w;\
1043181254a7Smrg	  newf.u.real.d = d - comp_d;\
1044181254a7Smrg	  newf.u.real.e = e;\
1045181254a7Smrg	  npad = 0;\
1046181254a7Smrg	  precision = determine_precision (dtp, &newf, x);\
1047181254a7Smrg	  nprinted = DTOA(y,precision,m);\
1048181254a7Smrg	}\
1049181254a7Smrg      else \
1050181254a7Smrg	{\
1051181254a7Smrg	  mid = 0;\
1052181254a7Smrg	  low = 0;\
1053181254a7Smrg	  high = d + 1;\
1054181254a7Smrg	  lbound = 0;\
1055181254a7Smrg	  ubound = d + 1;\
1056181254a7Smrg	  while (low <= high)\
1057181254a7Smrg	    {\
1058181254a7Smrg	      mid = (low + high) / 2;\
1059181254a7Smrg	      temp = (calculate_exp_ ## x (mid - 1) * r_sc);\
1060181254a7Smrg	      if (m < temp)\
1061181254a7Smrg		{ \
1062181254a7Smrg		  ubound = mid;\
1063181254a7Smrg		  if (ubound == lbound + 1)\
1064181254a7Smrg		    break;\
1065181254a7Smrg		  high = mid - 1;\
1066181254a7Smrg		}\
1067181254a7Smrg	      else if (m > temp)\
1068181254a7Smrg		{ \
1069181254a7Smrg		  lbound = mid;\
1070181254a7Smrg		  if (ubound == lbound + 1)\
1071181254a7Smrg		    { \
1072181254a7Smrg		      mid ++;\
1073181254a7Smrg		      break;\
1074181254a7Smrg		    }\
1075181254a7Smrg		  low = mid + 1;\
1076181254a7Smrg		}\
1077181254a7Smrg	      else\
1078181254a7Smrg		{\
1079181254a7Smrg		  mid++;\
1080181254a7Smrg		  break;\
1081181254a7Smrg		}\
1082181254a7Smrg	    }\
1083181254a7Smrg	  npad = e <= 0 ? 4 : e + 2;\
1084181254a7Smrg	  npad = npad >= w ? w - 1 : npad;\
1085181254a7Smrg	  npad = dtp->u.p.g0_no_blanks ? 0 : npad;\
1086181254a7Smrg	  newf.format = FMT_F;\
1087181254a7Smrg	  newf.u.real.w = w - npad;\
1088181254a7Smrg	  newf.u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
1089181254a7Smrg	  dtp->u.p.scale_factor = 0;\
1090181254a7Smrg	  precision = determine_precision (dtp, &newf, x);\
1091181254a7Smrg	  nprinted = FDTOA(y,precision,m);\
1092181254a7Smrg	}\
1093181254a7Smrg      build_float_string (dtp, &newf, buffer, size, nprinted, precision,\
1094fb8a8121Smrg				   sign_bit, zero_flag, npad, default_width,\
1095fb8a8121Smrg				   result, res_len);\
1096181254a7Smrg      dtp->u.p.scale_factor = save_scale_factor;\
1097181254a7Smrg    }\
1098181254a7Smrg  else\
1099181254a7Smrg    {\
1100181254a7Smrg      if (f->format == FMT_F)\
1101181254a7Smrg	nprinted = FDTOA(y,precision,m);\
1102181254a7Smrg      else\
1103181254a7Smrg	nprinted = DTOA(y,precision,m);\
1104181254a7Smrg      build_float_string (dtp, f, buffer, size, nprinted, precision,\
1105fb8a8121Smrg				   sign_bit, zero_flag, npad, default_width,\
1106fb8a8121Smrg				   result, res_len);\
1107181254a7Smrg    }\
1108181254a7Smrg}\
1109181254a7Smrg
1110181254a7Smrg/* Output a real number according to its format.  */
1111181254a7Smrg
1112181254a7Smrg
1113181254a7Smrgstatic void
1114181254a7Smrgget_float_string (st_parameter_dt *dtp, const fnode *f, const char *source,
1115181254a7Smrg		  int kind, int comp_d, char *buffer, int precision,
1116181254a7Smrg		  size_t size, char *result, size_t *res_len)
1117181254a7Smrg{
1118181254a7Smrg  int sign_bit, nprinted;
1119181254a7Smrg  bool zero_flag;
1120fb8a8121Smrg  int default_width = 0;
1121fb8a8121Smrg
1122fb8a8121Smrg  if (f->u.real.w == DEFAULT_WIDTH)
1123fb8a8121Smrg    /* This codepath can only be reached with -fdec-format-defaults. The default
1124fb8a8121Smrg     * values are based on those used in the Oracle Fortran compiler.
1125fb8a8121Smrg     */
1126fb8a8121Smrg    {
1127fb8a8121Smrg      default_width = default_width_for_float (kind);
1128fb8a8121Smrg      precision = default_precision_for_float (kind);
1129fb8a8121Smrg    }
1130181254a7Smrg
1131181254a7Smrg  switch (kind)
1132181254a7Smrg    {
1133181254a7Smrg    case 4:
1134181254a7Smrg      FORMAT_FLOAT(4,)
1135181254a7Smrg      break;
1136181254a7Smrg
1137181254a7Smrg    case 8:
1138181254a7Smrg      FORMAT_FLOAT(8,)
1139181254a7Smrg      break;
1140181254a7Smrg
1141181254a7Smrg#ifdef HAVE_GFC_REAL_10
1142181254a7Smrg    case 10:
1143181254a7Smrg      FORMAT_FLOAT(10,L)
1144181254a7Smrg      break;
1145181254a7Smrg#endif
1146181254a7Smrg#ifdef HAVE_GFC_REAL_16
1147181254a7Smrg    case 16:
1148181254a7Smrg# ifdef GFC_REAL_16_IS_FLOAT128
1149181254a7Smrg      FORMAT_FLOAT(16,Q)
1150181254a7Smrg# else
1151181254a7Smrg      FORMAT_FLOAT(16,L)
1152181254a7Smrg# endif
1153181254a7Smrg      break;
1154181254a7Smrg#endif
1155*b1e83836Smrg#ifdef HAVE_GFC_REAL_17
1156*b1e83836Smrg    case 17:
1157*b1e83836Smrg      FORMAT_FLOAT(17,Q)
1158*b1e83836Smrg      break;
1159*b1e83836Smrg#endif
1160181254a7Smrg    default:
1161181254a7Smrg      internal_error (NULL, "bad real kind");
1162181254a7Smrg    }
1163181254a7Smrg  return;
1164181254a7Smrg}
1165