]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgfortran/io/write_float.def
Update copyright years.
[thirdparty/gcc.git] / libgfortran / io / write_float.def
CommitLineData
fbd26352 1/* Copyright (C) 2007-2019 Free Software Foundation, Inc.
1f84fc76 2 Contributed by Andy Vaught
3 Write float code factoring to this file by Jerry DeLisle
84d33b91 4 F2003 I/O support contributed by Jerry DeLisle
1f84fc76 5
5e62a3cc 6This file is part of the GNU Fortran runtime library (libgfortran).
1f84fc76 7
8Libgfortran is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
6bc9506f 10the Free Software Foundation; either version 3, or (at your option)
1f84fc76 11any later version.
12
1f84fc76 13Libgfortran is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
6bc9506f 18Under Section 7 of GPL version 3, you are granted additional
19permissions described in the GCC Runtime Library Exception, version
203.1, as published by the Free Software Foundation.
21
22You should have received a copy of the GNU General Public License and
23a copy of the GCC Runtime Library Exception along with this program;
24see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25<http://www.gnu.org/licenses/>. */
1f84fc76 26
27#include "config.h"
28
29typedef enum
84d33b91 30{ S_NONE, S_MINUS, S_PLUS }
1f84fc76 31sign_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
36static sign_t
37calculate_sign (st_parameter_dt *dtp, int negative_flag)
38{
84d33b91 39 sign_t s = S_NONE;
1f84fc76 40
41 if (negative_flag)
84d33b91 42 s = S_MINUS;
1f84fc76 43 else
44 switch (dtp->u.p.sign_status)
45 {
84d33b91 46 case SIGN_SP: /* Show sign. */
47 s = S_PLUS;
1f84fc76 48 break;
84d33b91 49 case SIGN_SS: /* Suppress sign. */
50 s = S_NONE;
1f84fc76 51 break;
84d33b91 52 case SIGN_S: /* Processor defined. */
bc45c9ff 53 case SIGN_UNSPECIFIED:
84d33b91 54 s = options.optional_plus ? S_PLUS : S_NONE;
1f84fc76 55 break;
56 }
57
58 return s;
59}
60
61
acdec32d 62/* Determine the precision except for EN format. For G format,
63 determines an upper bound to be used for sizing the buffer. */
64
65static int
66determine_precision (st_parameter_dt * dtp, const fnode * f, int len)
67{
68 int precision = f->u.real.d;
69
70 switch (f->format)
71 {
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;
87 }
88
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;
96
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)
101 {
102 precision += 2 * len + 4;
103 if (precision < 0)
104 precision = 0;
105 }
106
107 return precision;
108}
109
110
88be2b3c 111/* Build a real number according to its format which is FMT_G free. */
1f84fc76 112
88be2b3c 113static void
114build_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)
1f84fc76 117{
88be2b3c 118 char *put;
1f84fc76 119 char *digits;
cc4f0493 120 int e, w, d, p, i;
7b00f2e9 121 char expchar, rchar;
1f84fc76 122 format_token ft;
1f84fc76 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;
1f84fc76 129 int leadzero;
130 int nblanks;
acdec32d 131 int ndigits, edigits;
1f84fc76 132 sign_t sign;
133
134 ft = f->format;
135 w = f->u.real.w;
136 d = f->u.real.d;
cc4f0493 137 p = dtp->u.p.scale_factor;
f904e489 138 *len = 0;
1f84fc76 139
7b00f2e9 140 rchar = '5';
1f84fc76 141
142 /* We should always know the field width and precision. */
143 if (d < 0)
144 internal_error (&dtp->common, "Unspecified precision");
145
1f84fc76 146 sign = calculate_sign (dtp, sign_bit);
fff1407e 147
acdec32d 148 /* Calculate total number of digits. */
149 if (ft == FMT_F)
150 ndigits = nprinted - 2;
151 else
152 ndigits = precision + 1;
1f84fc76 153
154 /* Read the exponent back in. */
acdec32d 155 if (ft != FMT_F)
156 e = atoi (&buffer[ndigits + 3]) + 1;
157 else
158 e = 0;
1f84fc76 159
160 /* Make sure zero comes out as 0.0e0. */
161 if (zero_flag)
1955b88d 162 e = 0;
1f84fc76 163
164 /* Normalize the fractional component. */
acdec32d 165 if (ft != FMT_F)
166 {
167 buffer[2] = buffer[1];
168 digits = &buffer[2];
169 }
170 else
171 digits = &buffer[1];
1f84fc76 172
173 /* Figure out where to place the decimal point. */
174 switch (ft)
175 {
176 case FMT_F:
acdec32d 177 nbefore = ndigits - precision;
45b4ec58 178 if ((w > 0) && (nbefore > (int) size))
179 {
180 *len = w;
181 star_fill (result, w);
182 result[w] = '\0';
183 return;
184 }
acdec32d 185 /* Make sure the decimal point is a '.'; depending on the
186 locale, this might not be the case otherwise. */
187 digits[nbefore] = '.';
acdec32d 188 if (p != 0)
1f84fc76 189 {
acdec32d 190 if (p > 0)
191 {
acdec32d 192 memmove (digits + nbefore, digits + nbefore + 1, p);
193 digits[nbefore + p] = '.';
194 nbefore += p;
acdec32d 195 nafter = d;
ff989d31 196 nzero = 0;
acdec32d 197 }
198 else /* p < 0 */
199 {
200 if (nbefore + p >= 0)
201 {
202 nzero = 0;
203 memmove (digits + nbefore + p + 1, digits + nbefore + p, -p);
204 nbefore += p;
205 digits[nbefore] = '.';
206 nafter = d;
207 }
208 else
209 {
210 nzero = -(nbefore + p);
211 memmove (digits + 1, digits, nbefore);
91c9586d 212 nafter = d - nzero;
213 if (nafter == 0 && d > 0)
214 {
215 /* This is needed to get the correct rounding. */
216 memmove (digits + 1, digits, ndigits - 1);
217 digits[1] = '0';
218 nafter = 1;
219 nzero = d - 1;
220 }
221 else if (nafter < 0)
222 {
223 /* Reset digits to 0 in order to get correct rounding
224 towards infinity. */
225 for (i = 0; i < ndigits; i++)
226 digits[i] = '0';
227 digits[ndigits - 1] = '1';
228 nafter = d;
229 nzero = 0;
230 }
acdec32d 231 nbefore = 0;
232 }
acdec32d 233 }
1f84fc76 234 }
235 else
236 {
ff989d31 237 nzero = 0;
1f84fc76 238 nafter = d;
239 }
acdec32d 240
06e6fdfb 241 while (digits[0] == '0' && nbefore > 0)
242 {
243 digits++;
244 nbefore--;
245 ndigits--;
246 }
247
1f84fc76 248 expchar = 0;
acdec32d 249 /* If we need to do rounding ourselves, get rid of the dot by
250 moving the fractional part. */
251 if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
252 && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
253 memmove (digits + nbefore, digits + nbefore + 1, ndigits - nbefore);
1f84fc76 254 break;
255
256 case FMT_E:
257 case FMT_D:
258 i = dtp->u.p.scale_factor;
cc4f0493 259 if (d <= 0 && p == 0)
e902a4d4 260 {
261 generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
262 "greater than zero in format specifier 'E' or 'D'");
88be2b3c 263 return;
e902a4d4 264 }
cc4f0493 265 if (p <= -d || p >= d + 2)
e902a4d4 266 {
267 generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
268 "out of range in format specifier 'E' or 'D'");
88be2b3c 269 return;
e902a4d4 270 }
271
1f84fc76 272 if (!zero_flag)
cc4f0493 273 e -= p;
274 if (p < 0)
1f84fc76 275 {
276 nbefore = 0;
cc4f0493 277 nzero = -p;
278 nafter = d + p;
1f84fc76 279 }
cc4f0493 280 else if (p > 0)
1f84fc76 281 {
cc4f0493 282 nbefore = p;
1f84fc76 283 nzero = 0;
cc4f0493 284 nafter = (d - p) + 1;
1f84fc76 285 }
cc4f0493 286 else /* p == 0 */
1f84fc76 287 {
288 nbefore = 0;
289 nzero = 0;
290 nafter = d;
291 }
292
293 if (ft == FMT_E)
294 expchar = 'E';
295 else
296 expchar = 'D';
297 break;
298
299 case FMT_EN:
300 /* The exponent must be a multiple of three, with 1-3 digits before
301 the decimal point. */
302 if (!zero_flag)
303 e--;
304 if (e >= 0)
305 nbefore = e % 3;
306 else
307 {
308 nbefore = (-e) % 3;
309 if (nbefore != 0)
310 nbefore = 3 - nbefore;
311 }
312 e -= nbefore;
313 nbefore++;
314 nzero = 0;
315 nafter = d;
316 expchar = 'E';
317 break;
318
319 case FMT_ES:
320 if (!zero_flag)
321 e--;
322 nbefore = 1;
323 nzero = 0;
324 nafter = d;
325 expchar = 'E';
326 break;
327
328 default:
329 /* Should never happen. */
330 internal_error (&dtp->common, "Unexpected format token");
331 }
332
7ae69d02 333 if (zero_flag)
334 goto skip;
5a0457f6 335
acdec32d 336 /* Round the value. The value being rounded is an unsigned magnitude. */
7b00f2e9 337 switch (dtp->u.p.current_unit->round_status)
338 {
acdec32d 339 /* For processor defined and unspecified rounding we use
340 snprintf to print the exact number of digits needed, and thus
341 let snprintf handle the rounding. On system claiming support
342 for IEEE 754, this ought to be round to nearest, ties to
343 even, corresponding to the Fortran ROUND='NEAREST'. */
344 case ROUND_PROCDEFINED:
345 case ROUND_UNSPECIFIED:
7b00f2e9 346 case ROUND_ZERO: /* Do nothing and truncation occurs. */
347 goto skip;
348 case ROUND_UP:
349 if (sign_bit)
350 goto skip;
5a0457f6 351 goto updown;
7b00f2e9 352 case ROUND_DOWN:
353 if (!sign_bit)
354 goto skip;
5a0457f6 355 goto updown;
7b00f2e9 356 case ROUND_NEAREST:
357 /* Round compatible unless there is a tie. A tie is a 5 with
358 all trailing zero's. */
7a21d377 359 i = nafter + nbefore;
7b00f2e9 360 if (digits[i] == '5')
361 {
362 for(i++ ; i < ndigits; i++)
363 {
364 if (digits[i] != '0')
365 goto do_rnd;
366 }
5a0457f6 367 /* It is a tie so round to even. */
7a21d377 368 switch (digits[nafter + nbefore - 1])
7b00f2e9 369 {
370 case '1':
371 case '3':
372 case '5':
373 case '7':
374 case '9':
375 /* If odd, round away from zero to even. */
376 break;
377 default:
378 /* If even, skip rounding, truncate to even. */
379 goto skip;
380 }
381 }
acdec32d 382 /* Fall through. */
383 /* The ROUND_COMPATIBLE is rounding away from zero when there is a tie. */
7b00f2e9 384 case ROUND_COMPATIBLE:
385 rchar = '5';
5a0457f6 386 goto do_rnd;
387 }
388
389 updown:
390
391 rchar = '0';
ff989d31 392 if (ft != FMT_F && w > 0 && d == 0 && p == 0)
5a0457f6 393 nbefore = 1;
394 /* Scan for trailing zeros to see if we really need to round it. */
395 for(i = nbefore + nafter; i < ndigits; i++)
396 {
397 if (digits[i] != '0')
398 goto do_rnd;
7b00f2e9 399 }
5a0457f6 400 goto skip;
7b00f2e9 401
402 do_rnd:
403
1f84fc76 404 if (nbefore + nafter == 0)
87aa609d 405 /* Handle the case Fw.0 and value < 1.0 */
1f84fc76 406 {
407 ndigits = 0;
805e2bf6 408 if (digits[0] >= rchar)
7b00f2e9 409 {
410 /* We rounded to zero but shouldn't have */
87aa609d 411 nbefore = 1;
412 digits--;
7b00f2e9 413 digits[0] = '1';
414 ndigits = 1;
415 }
1f84fc76 416 }
417 else if (nbefore + nafter < ndigits)
418 {
20b8800c 419 i = ndigits = nbefore + nafter;
7b00f2e9 420 if (digits[i] >= rchar)
1f84fc76 421 {
422 /* Propagate the carry. */
423 for (i--; i >= 0; i--)
424 {
425 if (digits[i] != '9')
426 {
427 digits[i]++;
428 break;
429 }
430 digits[i] = '0';
431 }
432
433 if (i < 0)
434 {
7b00f2e9 435 /* The carry overflowed. Fortunately we have some spare
436 space at the start of the buffer. We may discard some
437 digits, but this is ok because we already know they are
438 zero. */
1f84fc76 439 digits--;
440 digits[0] = '1';
441 if (ft == FMT_F)
442 {
443 if (nzero > 0)
444 {
445 nzero--;
446 nafter++;
447 }
448 else
449 nbefore++;
450 }
451 else if (ft == FMT_EN)
452 {
453 nbefore++;
454 if (nbefore == 4)
455 {
456 nbefore = 1;
457 e += 3;
458 }
459 }
460 else
461 e++;
462 }
463 }
464 }
465
7b00f2e9 466 skip:
467
1f84fc76 468 /* Calculate the format of the exponent field. */
09f979b0 469 if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
1f84fc76 470 {
471 edigits = 1;
472 for (i = abs (e); i >= 10; i /= 10)
473 edigits++;
474
475 if (f->u.real.e < 0)
476 {
477 /* Width not specified. Must be no more than 3 digits. */
478 if (e > 999 || e < -999)
479 edigits = -1;
480 else
481 {
482 edigits = 4;
483 if (e > 99 || e < -99)
484 expchar = ' ';
485 }
486 }
487 else
488 {
489 /* Exponent width specified, check it is wide enough. */
490 if (edigits > f->u.real.e)
491 edigits = -1;
492 else
493 edigits = f->u.real.e + 2;
494 }
495 }
496 else
497 edigits = 0;
498
1955b88d 499 /* Scan the digits string and count the number of zeros. If we make it
500 all the way through the loop, we know the value is zero after the
501 rounding completed above. */
49bbaf35 502 int hasdot = 0;
503 for (i = 0; i < ndigits + hasdot; i++)
1f84fc76 504 {
49bbaf35 505 if (digits[i] == '.')
506 hasdot = 1;
507 else if (digits[i] != '0')
1f84fc76 508 break;
509 }
1955b88d 510
511 /* To format properly, we need to know if the rounded result is zero and if
512 so, we set the zero_flag which may have been already set for
513 actual zero. */
49bbaf35 514 if (i == ndigits + hasdot)
1f84fc76 515 {
1955b88d 516 zero_flag = true;
1f84fc76 517 /* The output is zero, so set the sign according to the sign bit unless
518 -fno-sign-zero was specified. */
519 if (compile_options.sign_zero == 1)
520 sign = calculate_sign (dtp, sign_bit);
521 else
522 sign = calculate_sign (dtp, 0);
523 }
524
1955b88d 525 /* Pick a field size if none was specified, taking into account small
526 values that may have been rounded to zero. */
4749905d 527 if (w <= 0)
b67cfb58 528 {
1955b88d 529 if (zero_flag)
530 w = d + (sign != S_NONE ? 2 : 1) + (d == 0 ? 1 : 0);
531 else
532 {
533 w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1);
534 w = w == 1 ? 2 : w;
535 }
b67cfb58 536 }
3560af84 537
1f84fc76 538 /* Work out how much padding is needed. */
539 nblanks = w - (nbefore + nzero + nafter + edigits + 1);
84d33b91 540 if (sign != S_NONE)
1f84fc76 541 nblanks--;
542
3560af84 543 /* See if we have space for a zero before the decimal point. */
544 if (nbefore == 0 && nblanks > 0)
545 {
546 leadzero = 1;
547 nblanks--;
548 }
549 else
550 leadzero = 0;
551
4749905d 552 if (dtp->u.p.g0_no_blanks)
553 {
554 w -= nblanks;
555 nblanks = 0;
556 }
557
88be2b3c 558 /* Create the final float string. */
559 *len = w + npad;
560 put = result;
4749905d 561
1f84fc76 562 /* Check the value fits in the specified field width. */
b67cfb58 563 if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE))
1f84fc76 564 {
88be2b3c 565 star_fill (put, *len);
566 return;
1f84fc76 567 }
568
1f84fc76 569 /* Pad to full field width. */
1f84fc76 570 if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
571 {
88be2b3c 572 memset (put, ' ', nblanks);
573 put += nblanks;
1f84fc76 574 }
575
88be2b3c 576 /* Set the initial sign (if any). */
84d33b91 577 if (sign == S_PLUS)
88be2b3c 578 *(put++) = '+';
84d33b91 579 else if (sign == S_MINUS)
88be2b3c 580 *(put++) = '-';
1f84fc76 581
88be2b3c 582 /* Set an optional leading zero. */
1f84fc76 583 if (leadzero)
88be2b3c 584 *(put++) = '0';
1f84fc76 585
88be2b3c 586 /* Set the part before the decimal point, padding with zeros. */
1f84fc76 587 if (nbefore > 0)
588 {
589 if (nbefore > ndigits)
590 {
591 i = ndigits;
88be2b3c 592 memcpy (put, digits, i);
1f84fc76 593 ndigits = 0;
594 while (i < nbefore)
88be2b3c 595 put[i++] = '0';
1f84fc76 596 }
597 else
598 {
599 i = nbefore;
88be2b3c 600 memcpy (put, digits, i);
1f84fc76 601 ndigits -= i;
602 }
603
604 digits += i;
88be2b3c 605 put += nbefore;
1f84fc76 606 }
4749905d 607
88be2b3c 608 /* Set the decimal point. */
609 *(put++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
acdec32d 610 if (ft == FMT_F
611 && (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
612 || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
613 digits++;
1f84fc76 614
88be2b3c 615 /* Set leading zeros after the decimal point. */
1f84fc76 616 if (nzero > 0)
617 {
618 for (i = 0; i < nzero; i++)
88be2b3c 619 *(put++) = '0';
1f84fc76 620 }
621
88be2b3c 622 /* Set digits after the decimal point, padding with zeros. */
1f84fc76 623 if (nafter > 0)
624 {
625 if (nafter > ndigits)
626 i = ndigits;
627 else
628 i = nafter;
629
88be2b3c 630 memcpy (put, digits, i);
1f84fc76 631 while (i < nafter)
88be2b3c 632 put[i++] = '0';
1f84fc76 633
634 digits += i;
635 ndigits -= i;
88be2b3c 636 put += nafter;
1f84fc76 637 }
638
88be2b3c 639 /* Set the exponent. */
b7cd62a6 640 if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
1f84fc76 641 {
642 if (expchar != ' ')
643 {
88be2b3c 644 *(put++) = expchar;
1f84fc76 645 edigits--;
646 }
1f84fc76 647 snprintf (buffer, size, "%+0*d", edigits, e);
88be2b3c 648 memcpy (put, buffer, edigits);
649 put += edigits;
1f84fc76 650 }
4749905d 651
1f84fc76 652 if (dtp->u.p.no_leading_blank)
653 {
88be2b3c 654 memset (put , ' ' , nblanks);
1f84fc76 655 dtp->u.p.no_leading_blank = 0;
88be2b3c 656 put += nblanks;
657 }
658
659 if (npad > 0 && !dtp->u.p.g0_no_blanks)
660 {
661 memset (put , ' ' , npad);
662 put += npad;
1f84fc76 663 }
4749905d 664
88be2b3c 665 /* NULL terminate the string. */
666 *put = '\0';
667
668 return;
1f84fc76 669}
670
671
672/* Write "Infinite" or "Nan" as appropriate for the given format. */
673
674static void
88be2b3c 675build_infnan_string (st_parameter_dt *dtp, const fnode *f, int isnan_flag,
676 int sign_bit, char *p, size_t *len)
1f84fc76 677{
88be2b3c 678 char fin;
1f84fc76 679 int nb = 0;
12b90007 680 sign_t sign;
681 int mark;
1f84fc76 682
683 if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
684 {
12b90007 685 sign = calculate_sign (dtp, sign_bit);
686 mark = (sign == S_PLUS || sign == S_MINUS) ? 8 : 7;
687
e0aaacb7 688 nb = f->u.real.w;
88be2b3c 689 *len = nb;
edb1f420 690
e0aaacb7 691 /* If the field width is zero, the processor must select a width
692 not zero. 4 is chosen to allow output of '-Inf' or '+Inf' */
693
edb1f420 694 if ((nb == 0) || dtp->u.p.g0_no_blanks)
12b90007 695 {
696 if (isnan_flag)
697 nb = 3;
698 else
699 nb = (sign == S_PLUS || sign == S_MINUS) ? 4 : 3;
88be2b3c 700 *len = nb;
12b90007 701 }
88be2b3c 702
703 p[*len] = '\0';
e0aaacb7 704 if (nb < 3)
705 {
88be2b3c 706 memset (p, '*', nb);
e0aaacb7 707 return;
708 }
1f84fc76 709
88be2b3c 710 memset(p, ' ', nb);
1f84fc76 711
e0aaacb7 712 if (!isnan_flag)
713 {
714 if (sign_bit)
715 {
716 /* If the sign is negative and the width is 3, there is
717 insufficient room to output '-Inf', so output asterisks */
718 if (nb == 3)
719 {
88be2b3c 720 memset (p, '*', nb);
e0aaacb7 721 return;
722 }
723 /* The negative sign is mandatory */
724 fin = '-';
725 }
726 else
727 /* The positive sign is optional, but we output it for
728 consistency */
729 fin = '+';
730
12b90007 731 if (nb > mark)
e0aaacb7 732 /* We have room, so output 'Infinity' */
733 memcpy(p + nb - 8, "Infinity", 8);
734 else
735 /* For the case of width equals 8, there is not enough room
736 for the sign and 'Infinity' so we go with 'Inf' */
737 memcpy(p + nb - 3, "Inf", 3);
738
12b90007 739 if (sign == S_PLUS || sign == S_MINUS)
740 {
741 if (nb < 9 && nb > 3)
742 p[nb - 4] = fin; /* Put the sign in front of Inf */
743 else if (nb > 8)
744 p[nb - 9] = fin; /* Put the sign in front of Infinity */
745 }
e0aaacb7 746 }
747 else
88be2b3c 748 memcpy(p + nb - 3, "NaN", 3);
1f84fc76 749 }
e0aaacb7 750}
1f84fc76 751
752
753/* Returns the value of 10**d. */
754
755#define CALCULATE_EXP(x) \
15aefa66 756static GFC_REAL_ ## x \
1f84fc76 757calculate_exp_ ## x (int d)\
758{\
759 int i;\
760 GFC_REAL_ ## x r = 1.0;\
761 for (i = 0; i< (d >= 0 ? d : -d); i++)\
762 r *= 10;\
763 r = (d >= 0) ? r : 1.0 / r;\
764 return r;\
765}
766
767CALCULATE_EXP(4)
768
769CALCULATE_EXP(8)
770
771#ifdef HAVE_GFC_REAL_10
772CALCULATE_EXP(10)
773#endif
774
775#ifdef HAVE_GFC_REAL_16
776CALCULATE_EXP(16)
777#endif
778#undef CALCULATE_EXP
779
acdec32d 780
88be2b3c 781/* Define macros to build code for format_float. */
acdec32d 782
783 /* Note: Before output_float is called, snprintf is used to print to buffer the
784 number in the format +D.DDDDe+ddd.
785
786 # The result will always contain a decimal point, even if no
787 digits follow it
788
789 - The converted value is to be left adjusted on the field boundary
790
791 + A sign (+ or -) always be placed before a number
792
793 * prec is used as the precision
794
795 e format: [-]d.ddde±dd where there is one digit before the
796 decimal-point character and the number of digits after it is
797 equal to the precision. The exponent always contains at least two
798 digits; if the value is zero, the exponent is 00. */
799
800
801#define TOKENPASTE(x, y) TOKENPASTE2(x, y)
802#define TOKENPASTE2(x, y) x ## y
803
804#define DTOA(suff,prec,val) TOKENPASTE(DTOA2,suff)(prec,val)
805
88be2b3c 806#define DTOA2(prec,val) \
acdec32d 807snprintf (buffer, size, "%+-#.*e", (prec), (val))
808
88be2b3c 809#define DTOA2L(prec,val) \
acdec32d 810snprintf (buffer, size, "%+-#.*Le", (prec), (val))
811
812
813#if defined(GFC_REAL_16_IS_FLOAT128)
88be2b3c 814#define DTOA2Q(prec,val) \
72bad04d 815quadmath_snprintf (buffer, size, "%+-#.*Qe", (prec), (val))
acdec32d 816#endif
817
818#define FDTOA(suff,prec,val) TOKENPASTE(FDTOA2,suff)(prec,val)
819
820/* For F format, we print to the buffer with f format. */
88be2b3c 821#define FDTOA2(prec,val) \
acdec32d 822snprintf (buffer, size, "%+-#.*f", (prec), (val))
823
88be2b3c 824#define FDTOA2L(prec,val) \
acdec32d 825snprintf (buffer, size, "%+-#.*Lf", (prec), (val))
826
827
828#if defined(GFC_REAL_16_IS_FLOAT128)
88be2b3c 829#define FDTOA2Q(prec,val) \
72bad04d 830quadmath_snprintf (buffer, size, "%+-#.*Qf", \
acdec32d 831 (prec), (val))
832#endif
833
834
acdec32d 835/* EN format is tricky since the number of significant digits depends
836 on the magnitude. Solve it by first printing a temporary value and
837 figure out the number of significant digits from the printed
ff989d31 838 exponent. Values y, 0.95*10.0**e <= y <10.0**e, are rounded to
839 10.0**e even when the final result will not be rounded to 10.0**e.
840 For these values the exponent returned by atoi has to be decremented
841 by one. The values y in the ranges
842 (1000.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*(n+1))
843 (100.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+2)
844 (10.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+1)
845 are correctly rounded respectively to 1.0...0*10.0*(3*(n+1)),
846 100.0...0*10.0*(3*n), and 10.0...0*10.0*(3*n), where 0...0
847 represents d zeroes, by the lines 279 to 297. */
acdec32d 848#define EN_PREC(x,y)\
849{\
ff989d31 850 volatile GFC_REAL_ ## x tmp, one = 1.0;\
851 tmp = * (GFC_REAL_ ## x *)source;\
b8c06a06 852 if (isfinite (tmp))\
ff989d31 853 {\
854 nprinted = DTOA(y,0,tmp);\
855 int e = atoi (&buffer[4]);\
856 if (buffer[1] == '1')\
857 {\
858 tmp = (calculate_exp_ ## x (-e)) * tmp;\
88be2b3c 859 tmp = one - (tmp < 0 ? -tmp : tmp);\
ff989d31 860 if (tmp > 0)\
861 e = e - 1;\
862 }\
863 nbefore = e%3;\
864 if (nbefore < 0)\
865 nbefore = 3 + nbefore;\
866 }\
acdec32d 867 else\
868 nprinted = -1;\
869}\
fff1407e 870
acdec32d 871static int
872determine_en_precision (st_parameter_dt *dtp, const fnode *f,
873 const char *source, int len)
874{
875 int nprinted;
876 char buffer[10];
877 const size_t size = 10;
ff989d31 878 int nbefore; /* digits before decimal point - 1. */
fff1407e 879
acdec32d 880 switch (len)
881 {
882 case 4:
883 EN_PREC(4,)
884 break;
fff1407e 885
acdec32d 886 case 8:
887 EN_PREC(8,)
888 break;
1f84fc76 889
acdec32d 890#ifdef HAVE_GFC_REAL_10
891 case 10:
892 EN_PREC(10,L)
893 break;
894#endif
895#ifdef HAVE_GFC_REAL_16
896 case 16:
897# ifdef GFC_REAL_16_IS_FLOAT128
898 EN_PREC(16,Q)
899# else
900 EN_PREC(16,L)
901# endif
902 break;
903#endif
904 default:
905 internal_error (NULL, "bad real kind");
906 }
1f84fc76 907
acdec32d 908 if (nprinted == -1)
909 return -1;
1f84fc76 910
acdec32d 911 int prec = f->u.real.d + nbefore;
912 if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
913 && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
914 prec += 2 * len + 4;
915 return prec;
916}
917
87969c8c 918
88be2b3c 919/* Generate corresponding I/O format. and output.
920 The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
921 LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
922
923 Data Magnitude Equivalent Conversion
924 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
925 m = 0 F(w-n).(d-1), n' '
926 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
927 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
928 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
929 ................ ..........
930 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
931 m >= 10**d-0.5 Ew.d[Ee]
932
933 notes: for Gw.d , n' ' means 4 blanks
934 for Gw.dEe, n' ' means e+2 blanks
935 for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
936 the asm volatile is required for 32-bit x86 platforms. */
937#define FORMAT_FLOAT(x,y)\
1f84fc76 938{\
88be2b3c 939 int npad = 0;\
940 GFC_REAL_ ## x m;\
941 m = * (GFC_REAL_ ## x *)source;\
942 sign_bit = signbit (m);\
943 if (!isfinite (m))\
944 { \
945 build_infnan_string (dtp, f, isnan (m), sign_bit, result, res_len);\
946 return;\
947 }\
948 m = sign_bit ? -m : m;\
949 zero_flag = (m == 0.0);\
950 if (f->format == FMT_G)\
951 {\
952 int e = f->u.real.e;\
953 int d = f->u.real.d;\
954 int w = f->u.real.w;\
955 fnode newf;\
956 GFC_REAL_ ## x exp_d, r = 0.5, r_sc;\
957 int low, high, mid;\
958 int ubound, lbound;\
959 int save_scale_factor;\
960 volatile GFC_REAL_ ## x temp;\
961 save_scale_factor = dtp->u.p.scale_factor;\
962 switch (dtp->u.p.current_unit->round_status)\
963 {\
964 case ROUND_ZERO:\
965 r = sign_bit ? 1.0 : 0.0;\
966 break;\
967 case ROUND_UP:\
968 r = 1.0;\
969 break;\
970 case ROUND_DOWN:\
971 r = 0.0;\
972 break;\
973 default:\
974 break;\
975 }\
976 exp_d = calculate_exp_ ## x (d);\
977 r_sc = (1 - r / exp_d);\
978 temp = 0.1 * r_sc;\
979 if ((m > 0.0 && ((m < temp) || (r >= (exp_d - m))))\
980 || ((m == 0.0) && !(compile_options.allow_std\
981 & (GFC_STD_F2003 | GFC_STD_F2008)))\
982 || d == 0)\
983 { \
984 newf.format = FMT_E;\
985 newf.u.real.w = w;\
986 newf.u.real.d = d - comp_d;\
987 newf.u.real.e = e;\
988 npad = 0;\
989 precision = determine_precision (dtp, &newf, x);\
990 nprinted = DTOA(y,precision,m);\
991 }\
992 else \
993 {\
994 mid = 0;\
995 low = 0;\
996 high = d + 1;\
997 lbound = 0;\
998 ubound = d + 1;\
999 while (low <= high)\
1000 {\
1001 mid = (low + high) / 2;\
1002 temp = (calculate_exp_ ## x (mid - 1) * r_sc);\
1003 if (m < temp)\
1004 { \
1005 ubound = mid;\
1006 if (ubound == lbound + 1)\
1007 break;\
1008 high = mid - 1;\
1009 }\
1010 else if (m > temp)\
1011 { \
1012 lbound = mid;\
1013 if (ubound == lbound + 1)\
1014 { \
1015 mid ++;\
1016 break;\
1017 }\
1018 low = mid + 1;\
1019 }\
1020 else\
1021 {\
1022 mid++;\
1023 break;\
1024 }\
1025 }\
1026 npad = e <= 0 ? 4 : e + 2;\
1027 npad = npad >= w ? w - 1 : npad;\
1028 npad = dtp->u.p.g0_no_blanks ? 0 : npad;\
1029 newf.format = FMT_F;\
1030 newf.u.real.w = w - npad;\
1031 newf.u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
1032 dtp->u.p.scale_factor = 0;\
1033 precision = determine_precision (dtp, &newf, x);\
1034 nprinted = FDTOA(y,precision,m);\
1035 }\
1036 build_float_string (dtp, &newf, buffer, size, nprinted, precision,\
1037 sign_bit, zero_flag, npad, result, res_len);\
1038 dtp->u.p.scale_factor = save_scale_factor;\
1039 }\
1040 else\
1041 {\
1042 if (f->format == FMT_F)\
1043 nprinted = FDTOA(y,precision,m);\
1044 else\
1045 nprinted = DTOA(y,precision,m);\
1046 build_float_string (dtp, f, buffer, size, nprinted, precision,\
1047 sign_bit, zero_flag, npad, result, res_len);\
1048 }\
1f84fc76 1049}\
1050
1051/* Output a real number according to its format. */
1052
88be2b3c 1053
1f84fc76 1054static void
88be2b3c 1055get_float_string (st_parameter_dt *dtp, const fnode *f, const char *source,
1056 int kind, int comp_d, char *buffer, int precision,
1057 size_t size, char *result, size_t *res_len)
1f84fc76 1058{
acdec32d 1059 int sign_bit, nprinted;
1f84fc76 1060 bool zero_flag;
1f84fc76 1061
88be2b3c 1062 switch (kind)
1f84fc76 1063 {
1064 case 4:
88be2b3c 1065 FORMAT_FLOAT(4,)
1f84fc76 1066 break;
1067
1068 case 8:
88be2b3c 1069 FORMAT_FLOAT(8,)
1f84fc76 1070 break;
1071
1072#ifdef HAVE_GFC_REAL_10
1073 case 10:
88be2b3c 1074 FORMAT_FLOAT(10,L)
1f84fc76 1075 break;
1076#endif
1077#ifdef HAVE_GFC_REAL_16
1078 case 16:
87969c8c 1079# ifdef GFC_REAL_16_IS_FLOAT128
88be2b3c 1080 FORMAT_FLOAT(16,Q)
87969c8c 1081# else
88be2b3c 1082 FORMAT_FLOAT(16,L)
87969c8c 1083# endif
1f84fc76 1084 break;
1085#endif
1086 default:
1087 internal_error (NULL, "bad real kind");
1088 }
88be2b3c 1089 return;
1f84fc76 1090}