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