1*4c3eb207Smrg/* Copyright (C) 2007-2020 Free Software Foundation, Inc. 2627f7eb2Smrg Contributed by Andy Vaught 3627f7eb2Smrg Write float code factoring to this file by Jerry DeLisle 4627f7eb2Smrg F2003 I/O support contributed by Jerry DeLisle 5627f7eb2Smrg 6627f7eb2SmrgThis file is part of the GNU Fortran runtime library (libgfortran). 7627f7eb2Smrg 8627f7eb2SmrgLibgfortran is free software; you can redistribute it and/or modify 9627f7eb2Smrgit under the terms of the GNU General Public License as published by 10627f7eb2Smrgthe Free Software Foundation; either version 3, or (at your option) 11627f7eb2Smrgany later version. 12627f7eb2Smrg 13627f7eb2SmrgLibgfortran is distributed in the hope that it will be useful, 14627f7eb2Smrgbut WITHOUT ANY WARRANTY; without even the implied warranty of 15627f7eb2SmrgMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16627f7eb2SmrgGNU General Public License for more details. 17627f7eb2Smrg 18627f7eb2SmrgUnder Section 7 of GPL version 3, you are granted additional 19627f7eb2Smrgpermissions described in the GCC Runtime Library Exception, version 20627f7eb2Smrg3.1, as published by the Free Software Foundation. 21627f7eb2Smrg 22627f7eb2SmrgYou should have received a copy of the GNU General Public License and 23627f7eb2Smrga copy of the GCC Runtime Library Exception along with this program; 24627f7eb2Smrgsee the files COPYING3 and COPYING.RUNTIME respectively. If not, see 25627f7eb2Smrg<http://www.gnu.org/licenses/>. */ 26627f7eb2Smrg 27627f7eb2Smrg#include "config.h" 28627f7eb2Smrg 29627f7eb2Smrgtypedef enum 30627f7eb2Smrg{ S_NONE, S_MINUS, S_PLUS } 31627f7eb2Smrgsign_t; 32627f7eb2Smrg 33627f7eb2Smrg/* Given a flag that indicates if a value is negative or not, return a 34627f7eb2Smrg sign_t that gives the sign that we need to produce. */ 35627f7eb2Smrg 36627f7eb2Smrgstatic sign_t 37627f7eb2Smrgcalculate_sign (st_parameter_dt *dtp, int negative_flag) 38627f7eb2Smrg{ 39627f7eb2Smrg sign_t s = S_NONE; 40627f7eb2Smrg 41627f7eb2Smrg if (negative_flag) 42627f7eb2Smrg s = S_MINUS; 43627f7eb2Smrg else 44627f7eb2Smrg switch (dtp->u.p.sign_status) 45627f7eb2Smrg { 46627f7eb2Smrg case SIGN_SP: /* Show sign. */ 47627f7eb2Smrg s = S_PLUS; 48627f7eb2Smrg break; 49627f7eb2Smrg case SIGN_SS: /* Suppress sign. */ 50627f7eb2Smrg s = S_NONE; 51627f7eb2Smrg break; 52627f7eb2Smrg case SIGN_S: /* Processor defined. */ 53627f7eb2Smrg case SIGN_UNSPECIFIED: 54627f7eb2Smrg s = options.optional_plus ? S_PLUS : S_NONE; 55627f7eb2Smrg break; 56627f7eb2Smrg } 57627f7eb2Smrg 58627f7eb2Smrg return s; 59627f7eb2Smrg} 60627f7eb2Smrg 61627f7eb2Smrg 62627f7eb2Smrg/* Determine the precision except for EN format. For G format, 63627f7eb2Smrg determines an upper bound to be used for sizing the buffer. */ 64627f7eb2Smrg 65627f7eb2Smrgstatic int 66627f7eb2Smrgdetermine_precision (st_parameter_dt * dtp, const fnode * f, int len) 67627f7eb2Smrg{ 68627f7eb2Smrg int precision = f->u.real.d; 69627f7eb2Smrg 70627f7eb2Smrg switch (f->format) 71627f7eb2Smrg { 72627f7eb2Smrg case FMT_F: 73627f7eb2Smrg case FMT_G: 74627f7eb2Smrg precision += dtp->u.p.scale_factor; 75627f7eb2Smrg break; 76627f7eb2Smrg case FMT_ES: 77627f7eb2Smrg /* Scale factor has no effect on output. */ 78627f7eb2Smrg break; 79627f7eb2Smrg case FMT_E: 80627f7eb2Smrg case FMT_D: 81627f7eb2Smrg /* See F2008 10.7.2.3.3.6 */ 82627f7eb2Smrg if (dtp->u.p.scale_factor <= 0) 83627f7eb2Smrg precision += dtp->u.p.scale_factor - 1; 84627f7eb2Smrg break; 85627f7eb2Smrg default: 86627f7eb2Smrg return -1; 87627f7eb2Smrg } 88627f7eb2Smrg 89627f7eb2Smrg /* If the scale factor has a large negative value, we must do our 90627f7eb2Smrg own rounding? Use ROUND='NEAREST', which should be what snprintf 91627f7eb2Smrg is using as well. */ 92627f7eb2Smrg if (precision < 0 && 93627f7eb2Smrg (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED 94627f7eb2Smrg || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED)) 95627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_NEAREST; 96627f7eb2Smrg 97627f7eb2Smrg /* Add extra guard digits up to at least full precision when we do 98627f7eb2Smrg our own rounding. */ 99627f7eb2Smrg if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED 100627f7eb2Smrg && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED) 101627f7eb2Smrg { 102627f7eb2Smrg precision += 2 * len + 4; 103627f7eb2Smrg if (precision < 0) 104627f7eb2Smrg precision = 0; 105627f7eb2Smrg } 106627f7eb2Smrg 107627f7eb2Smrg return precision; 108627f7eb2Smrg} 109627f7eb2Smrg 110627f7eb2Smrg 111627f7eb2Smrg/* Build a real number according to its format which is FMT_G free. */ 112627f7eb2Smrg 113627f7eb2Smrgstatic void 114627f7eb2Smrgbuild_float_string (st_parameter_dt *dtp, const fnode *f, char *buffer, 115627f7eb2Smrg size_t size, int nprinted, int precision, int sign_bit, 116*4c3eb207Smrg bool zero_flag, int npad, int default_width, char *result, 117*4c3eb207Smrg size_t *len) 118627f7eb2Smrg{ 119627f7eb2Smrg char *put; 120627f7eb2Smrg char *digits; 121627f7eb2Smrg int e, w, d, p, i; 122627f7eb2Smrg char expchar, rchar; 123627f7eb2Smrg format_token ft; 124627f7eb2Smrg /* Number of digits before the decimal point. */ 125627f7eb2Smrg int nbefore; 126627f7eb2Smrg /* Number of zeros after the decimal point. */ 127627f7eb2Smrg int nzero; 128627f7eb2Smrg /* Number of digits after the decimal point. */ 129627f7eb2Smrg int nafter; 130627f7eb2Smrg int leadzero; 131627f7eb2Smrg int nblanks; 132627f7eb2Smrg int ndigits, edigits; 133627f7eb2Smrg sign_t sign; 134627f7eb2Smrg 135627f7eb2Smrg ft = f->format; 136*4c3eb207Smrg if (f->u.real.w == DEFAULT_WIDTH) 137*4c3eb207Smrg /* This codepath can only be reached with -fdec-format-defaults. */ 138*4c3eb207Smrg { 139*4c3eb207Smrg w = default_width; 140*4c3eb207Smrg d = precision; 141*4c3eb207Smrg } 142*4c3eb207Smrg else 143*4c3eb207Smrg { 144627f7eb2Smrg w = f->u.real.w; 145627f7eb2Smrg d = f->u.real.d; 146*4c3eb207Smrg } 147627f7eb2Smrg p = dtp->u.p.scale_factor; 148627f7eb2Smrg *len = 0; 149627f7eb2Smrg 150627f7eb2Smrg rchar = '5'; 151627f7eb2Smrg 152627f7eb2Smrg /* We should always know the field width and precision. */ 153627f7eb2Smrg if (d < 0) 154627f7eb2Smrg internal_error (&dtp->common, "Unspecified precision"); 155627f7eb2Smrg 156627f7eb2Smrg sign = calculate_sign (dtp, sign_bit); 157627f7eb2Smrg 158627f7eb2Smrg /* Calculate total number of digits. */ 159627f7eb2Smrg if (ft == FMT_F) 160627f7eb2Smrg ndigits = nprinted - 2; 161627f7eb2Smrg else 162627f7eb2Smrg ndigits = precision + 1; 163627f7eb2Smrg 164627f7eb2Smrg /* Read the exponent back in. */ 165627f7eb2Smrg if (ft != FMT_F) 166627f7eb2Smrg e = atoi (&buffer[ndigits + 3]) + 1; 167627f7eb2Smrg else 168627f7eb2Smrg e = 0; 169627f7eb2Smrg 170627f7eb2Smrg /* Make sure zero comes out as 0.0e0. */ 171627f7eb2Smrg if (zero_flag) 172627f7eb2Smrg e = 0; 173627f7eb2Smrg 174627f7eb2Smrg /* Normalize the fractional component. */ 175627f7eb2Smrg if (ft != FMT_F) 176627f7eb2Smrg { 177627f7eb2Smrg buffer[2] = buffer[1]; 178627f7eb2Smrg digits = &buffer[2]; 179627f7eb2Smrg } 180627f7eb2Smrg else 181627f7eb2Smrg digits = &buffer[1]; 182627f7eb2Smrg 183627f7eb2Smrg /* Figure out where to place the decimal point. */ 184627f7eb2Smrg switch (ft) 185627f7eb2Smrg { 186627f7eb2Smrg case FMT_F: 187627f7eb2Smrg nbefore = ndigits - precision; 188627f7eb2Smrg if ((w > 0) && (nbefore > (int) size)) 189627f7eb2Smrg { 190627f7eb2Smrg *len = w; 191627f7eb2Smrg star_fill (result, w); 192627f7eb2Smrg result[w] = '\0'; 193627f7eb2Smrg return; 194627f7eb2Smrg } 195627f7eb2Smrg /* Make sure the decimal point is a '.'; depending on the 196627f7eb2Smrg locale, this might not be the case otherwise. */ 197627f7eb2Smrg digits[nbefore] = '.'; 198627f7eb2Smrg if (p != 0) 199627f7eb2Smrg { 200627f7eb2Smrg if (p > 0) 201627f7eb2Smrg { 202627f7eb2Smrg memmove (digits + nbefore, digits + nbefore + 1, p); 203627f7eb2Smrg digits[nbefore + p] = '.'; 204627f7eb2Smrg nbefore += p; 205627f7eb2Smrg nafter = d; 206627f7eb2Smrg nzero = 0; 207627f7eb2Smrg } 208627f7eb2Smrg else /* p < 0 */ 209627f7eb2Smrg { 210627f7eb2Smrg if (nbefore + p >= 0) 211627f7eb2Smrg { 212627f7eb2Smrg nzero = 0; 213627f7eb2Smrg memmove (digits + nbefore + p + 1, digits + nbefore + p, -p); 214627f7eb2Smrg nbefore += p; 215627f7eb2Smrg digits[nbefore] = '.'; 216627f7eb2Smrg nafter = d; 217627f7eb2Smrg } 218627f7eb2Smrg else 219627f7eb2Smrg { 220627f7eb2Smrg nzero = -(nbefore + p); 221627f7eb2Smrg memmove (digits + 1, digits, nbefore); 222627f7eb2Smrg nafter = d - nzero; 223627f7eb2Smrg if (nafter == 0 && d > 0) 224627f7eb2Smrg { 225627f7eb2Smrg /* This is needed to get the correct rounding. */ 226627f7eb2Smrg memmove (digits + 1, digits, ndigits - 1); 227627f7eb2Smrg digits[1] = '0'; 228627f7eb2Smrg nafter = 1; 229627f7eb2Smrg nzero = d - 1; 230627f7eb2Smrg } 231627f7eb2Smrg else if (nafter < 0) 232627f7eb2Smrg { 233627f7eb2Smrg /* Reset digits to 0 in order to get correct rounding 234627f7eb2Smrg towards infinity. */ 235627f7eb2Smrg for (i = 0; i < ndigits; i++) 236627f7eb2Smrg digits[i] = '0'; 237627f7eb2Smrg digits[ndigits - 1] = '1'; 238627f7eb2Smrg nafter = d; 239627f7eb2Smrg nzero = 0; 240627f7eb2Smrg } 241627f7eb2Smrg nbefore = 0; 242627f7eb2Smrg } 243627f7eb2Smrg } 244627f7eb2Smrg } 245627f7eb2Smrg else 246627f7eb2Smrg { 247627f7eb2Smrg nzero = 0; 248627f7eb2Smrg nafter = d; 249627f7eb2Smrg } 250627f7eb2Smrg 251627f7eb2Smrg while (digits[0] == '0' && nbefore > 0) 252627f7eb2Smrg { 253627f7eb2Smrg digits++; 254627f7eb2Smrg nbefore--; 255627f7eb2Smrg ndigits--; 256627f7eb2Smrg } 257627f7eb2Smrg 258627f7eb2Smrg expchar = 0; 259627f7eb2Smrg /* If we need to do rounding ourselves, get rid of the dot by 260627f7eb2Smrg moving the fractional part. */ 261627f7eb2Smrg if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED 262627f7eb2Smrg && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED) 263627f7eb2Smrg memmove (digits + nbefore, digits + nbefore + 1, ndigits - nbefore); 264627f7eb2Smrg break; 265627f7eb2Smrg 266627f7eb2Smrg case FMT_E: 267627f7eb2Smrg case FMT_D: 268627f7eb2Smrg i = dtp->u.p.scale_factor; 269*4c3eb207Smrg if (d < 0 && p == 0) 270627f7eb2Smrg { 271627f7eb2Smrg generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not " 272627f7eb2Smrg "greater than zero in format specifier 'E' or 'D'"); 273627f7eb2Smrg return; 274627f7eb2Smrg } 275627f7eb2Smrg if (p <= -d || p >= d + 2) 276627f7eb2Smrg { 277627f7eb2Smrg generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor " 278627f7eb2Smrg "out of range in format specifier 'E' or 'D'"); 279627f7eb2Smrg return; 280627f7eb2Smrg } 281627f7eb2Smrg 282627f7eb2Smrg if (!zero_flag) 283627f7eb2Smrg e -= p; 284627f7eb2Smrg if (p < 0) 285627f7eb2Smrg { 286627f7eb2Smrg nbefore = 0; 287627f7eb2Smrg nzero = -p; 288627f7eb2Smrg nafter = d + p; 289627f7eb2Smrg } 290627f7eb2Smrg else if (p > 0) 291627f7eb2Smrg { 292627f7eb2Smrg nbefore = p; 293627f7eb2Smrg nzero = 0; 294627f7eb2Smrg nafter = (d - p) + 1; 295627f7eb2Smrg } 296627f7eb2Smrg else /* p == 0 */ 297627f7eb2Smrg { 298627f7eb2Smrg nbefore = 0; 299627f7eb2Smrg nzero = 0; 300627f7eb2Smrg nafter = d; 301627f7eb2Smrg } 302627f7eb2Smrg 303627f7eb2Smrg if (ft == FMT_E) 304627f7eb2Smrg expchar = 'E'; 305627f7eb2Smrg else 306627f7eb2Smrg expchar = 'D'; 307627f7eb2Smrg break; 308627f7eb2Smrg 309627f7eb2Smrg case FMT_EN: 310627f7eb2Smrg /* The exponent must be a multiple of three, with 1-3 digits before 311627f7eb2Smrg the decimal point. */ 312627f7eb2Smrg if (!zero_flag) 313627f7eb2Smrg e--; 314627f7eb2Smrg if (e >= 0) 315627f7eb2Smrg nbefore = e % 3; 316627f7eb2Smrg else 317627f7eb2Smrg { 318627f7eb2Smrg nbefore = (-e) % 3; 319627f7eb2Smrg if (nbefore != 0) 320627f7eb2Smrg nbefore = 3 - nbefore; 321627f7eb2Smrg } 322627f7eb2Smrg e -= nbefore; 323627f7eb2Smrg nbefore++; 324627f7eb2Smrg nzero = 0; 325627f7eb2Smrg nafter = d; 326627f7eb2Smrg expchar = 'E'; 327627f7eb2Smrg break; 328627f7eb2Smrg 329627f7eb2Smrg case FMT_ES: 330627f7eb2Smrg if (!zero_flag) 331627f7eb2Smrg e--; 332627f7eb2Smrg nbefore = 1; 333627f7eb2Smrg nzero = 0; 334627f7eb2Smrg nafter = d; 335627f7eb2Smrg expchar = 'E'; 336627f7eb2Smrg break; 337627f7eb2Smrg 338627f7eb2Smrg default: 339627f7eb2Smrg /* Should never happen. */ 340627f7eb2Smrg internal_error (&dtp->common, "Unexpected format token"); 341627f7eb2Smrg } 342627f7eb2Smrg 343627f7eb2Smrg if (zero_flag) 344627f7eb2Smrg goto skip; 345627f7eb2Smrg 346627f7eb2Smrg /* Round the value. The value being rounded is an unsigned magnitude. */ 347627f7eb2Smrg switch (dtp->u.p.current_unit->round_status) 348627f7eb2Smrg { 349627f7eb2Smrg /* For processor defined and unspecified rounding we use 350627f7eb2Smrg snprintf to print the exact number of digits needed, and thus 351627f7eb2Smrg let snprintf handle the rounding. On system claiming support 352627f7eb2Smrg for IEEE 754, this ought to be round to nearest, ties to 353627f7eb2Smrg even, corresponding to the Fortran ROUND='NEAREST'. */ 354627f7eb2Smrg case ROUND_PROCDEFINED: 355627f7eb2Smrg case ROUND_UNSPECIFIED: 356627f7eb2Smrg case ROUND_ZERO: /* Do nothing and truncation occurs. */ 357627f7eb2Smrg goto skip; 358627f7eb2Smrg case ROUND_UP: 359627f7eb2Smrg if (sign_bit) 360627f7eb2Smrg goto skip; 361627f7eb2Smrg goto updown; 362627f7eb2Smrg case ROUND_DOWN: 363627f7eb2Smrg if (!sign_bit) 364627f7eb2Smrg goto skip; 365627f7eb2Smrg goto updown; 366627f7eb2Smrg case ROUND_NEAREST: 367627f7eb2Smrg /* Round compatible unless there is a tie. A tie is a 5 with 368627f7eb2Smrg all trailing zero's. */ 369627f7eb2Smrg i = nafter + nbefore; 370627f7eb2Smrg if (digits[i] == '5') 371627f7eb2Smrg { 372627f7eb2Smrg for(i++ ; i < ndigits; i++) 373627f7eb2Smrg { 374627f7eb2Smrg if (digits[i] != '0') 375627f7eb2Smrg goto do_rnd; 376627f7eb2Smrg } 377627f7eb2Smrg /* It is a tie so round to even. */ 378627f7eb2Smrg switch (digits[nafter + nbefore - 1]) 379627f7eb2Smrg { 380627f7eb2Smrg case '1': 381627f7eb2Smrg case '3': 382627f7eb2Smrg case '5': 383627f7eb2Smrg case '7': 384627f7eb2Smrg case '9': 385627f7eb2Smrg /* If odd, round away from zero to even. */ 386627f7eb2Smrg break; 387627f7eb2Smrg default: 388627f7eb2Smrg /* If even, skip rounding, truncate to even. */ 389627f7eb2Smrg goto skip; 390627f7eb2Smrg } 391627f7eb2Smrg } 392627f7eb2Smrg /* Fall through. */ 393627f7eb2Smrg /* The ROUND_COMPATIBLE is rounding away from zero when there is a tie. */ 394627f7eb2Smrg case ROUND_COMPATIBLE: 395627f7eb2Smrg rchar = '5'; 396627f7eb2Smrg goto do_rnd; 397627f7eb2Smrg } 398627f7eb2Smrg 399627f7eb2Smrg updown: 400627f7eb2Smrg 401627f7eb2Smrg rchar = '0'; 402*4c3eb207Smrg /* Do not reset nbefore for FMT_F and FMT_EN. */ 403*4c3eb207Smrg if (ft != FMT_F && ft !=FMT_EN && w > 0 && d == 0 && p == 0) 404627f7eb2Smrg nbefore = 1; 405627f7eb2Smrg /* Scan for trailing zeros to see if we really need to round it. */ 406627f7eb2Smrg for(i = nbefore + nafter; i < ndigits; i++) 407627f7eb2Smrg { 408627f7eb2Smrg if (digits[i] != '0') 409627f7eb2Smrg goto do_rnd; 410627f7eb2Smrg } 411627f7eb2Smrg goto skip; 412627f7eb2Smrg 413627f7eb2Smrg do_rnd: 414627f7eb2Smrg 415627f7eb2Smrg if (nbefore + nafter == 0) 416627f7eb2Smrg /* Handle the case Fw.0 and value < 1.0 */ 417627f7eb2Smrg { 418627f7eb2Smrg ndigits = 0; 419627f7eb2Smrg if (digits[0] >= rchar) 420627f7eb2Smrg { 421627f7eb2Smrg /* We rounded to zero but shouldn't have */ 422627f7eb2Smrg nbefore = 1; 423627f7eb2Smrg digits--; 424627f7eb2Smrg digits[0] = '1'; 425627f7eb2Smrg ndigits = 1; 426627f7eb2Smrg } 427627f7eb2Smrg } 428627f7eb2Smrg else if (nbefore + nafter < ndigits) 429627f7eb2Smrg { 430627f7eb2Smrg i = ndigits = nbefore + nafter; 431627f7eb2Smrg if (digits[i] >= rchar) 432627f7eb2Smrg { 433627f7eb2Smrg /* Propagate the carry. */ 434627f7eb2Smrg for (i--; i >= 0; i--) 435627f7eb2Smrg { 436627f7eb2Smrg if (digits[i] != '9') 437627f7eb2Smrg { 438627f7eb2Smrg digits[i]++; 439627f7eb2Smrg break; 440627f7eb2Smrg } 441627f7eb2Smrg digits[i] = '0'; 442627f7eb2Smrg } 443627f7eb2Smrg 444627f7eb2Smrg if (i < 0) 445627f7eb2Smrg { 446627f7eb2Smrg /* The carry overflowed. Fortunately we have some spare 447627f7eb2Smrg space at the start of the buffer. We may discard some 448627f7eb2Smrg digits, but this is ok because we already know they are 449627f7eb2Smrg zero. */ 450627f7eb2Smrg digits--; 451627f7eb2Smrg digits[0] = '1'; 452627f7eb2Smrg if (ft == FMT_F) 453627f7eb2Smrg { 454627f7eb2Smrg if (nzero > 0) 455627f7eb2Smrg { 456627f7eb2Smrg nzero--; 457627f7eb2Smrg nafter++; 458627f7eb2Smrg } 459627f7eb2Smrg else 460627f7eb2Smrg nbefore++; 461627f7eb2Smrg } 462627f7eb2Smrg else if (ft == FMT_EN) 463627f7eb2Smrg { 464627f7eb2Smrg nbefore++; 465627f7eb2Smrg if (nbefore == 4) 466627f7eb2Smrg { 467627f7eb2Smrg nbefore = 1; 468627f7eb2Smrg e += 3; 469627f7eb2Smrg } 470627f7eb2Smrg } 471627f7eb2Smrg else 472627f7eb2Smrg e++; 473627f7eb2Smrg } 474627f7eb2Smrg } 475627f7eb2Smrg } 476627f7eb2Smrg 477627f7eb2Smrg skip: 478627f7eb2Smrg 479627f7eb2Smrg /* Calculate the format of the exponent field. */ 480627f7eb2Smrg if (expchar && !(dtp->u.p.g0_no_blanks && e == 0)) 481627f7eb2Smrg { 482627f7eb2Smrg edigits = 1; 483627f7eb2Smrg for (i = abs (e); i >= 10; i /= 10) 484627f7eb2Smrg edigits++; 485627f7eb2Smrg 486627f7eb2Smrg if (f->u.real.e < 0) 487627f7eb2Smrg { 488627f7eb2Smrg /* Width not specified. Must be no more than 3 digits. */ 489627f7eb2Smrg if (e > 999 || e < -999) 490627f7eb2Smrg edigits = -1; 491627f7eb2Smrg else 492627f7eb2Smrg { 493627f7eb2Smrg edigits = 4; 494627f7eb2Smrg if (e > 99 || e < -99) 495627f7eb2Smrg expchar = ' '; 496627f7eb2Smrg } 497627f7eb2Smrg } 498*4c3eb207Smrg else if (f->u.real.e == 0) 499*4c3eb207Smrg { 500*4c3eb207Smrg /* Zero width specified, no leading zeros in exponent */ 501*4c3eb207Smrg if (e > 999 || e < -999) 502*4c3eb207Smrg edigits = 6; 503*4c3eb207Smrg else if (e > 99 || e < -99) 504*4c3eb207Smrg edigits = 5; 505*4c3eb207Smrg else if (e > 9 || e < -9) 506*4c3eb207Smrg edigits = 4; 507*4c3eb207Smrg else 508*4c3eb207Smrg edigits = 3; 509*4c3eb207Smrg } 510627f7eb2Smrg else 511627f7eb2Smrg { 512627f7eb2Smrg /* Exponent width specified, check it is wide enough. */ 513627f7eb2Smrg if (edigits > f->u.real.e) 514627f7eb2Smrg edigits = -1; 515627f7eb2Smrg else 516627f7eb2Smrg edigits = f->u.real.e + 2; 517627f7eb2Smrg } 518627f7eb2Smrg } 519627f7eb2Smrg else 520627f7eb2Smrg edigits = 0; 521627f7eb2Smrg 522627f7eb2Smrg /* Scan the digits string and count the number of zeros. If we make it 523627f7eb2Smrg all the way through the loop, we know the value is zero after the 524627f7eb2Smrg rounding completed above. */ 525627f7eb2Smrg int hasdot = 0; 526627f7eb2Smrg for (i = 0; i < ndigits + hasdot; i++) 527627f7eb2Smrg { 528627f7eb2Smrg if (digits[i] == '.') 529627f7eb2Smrg hasdot = 1; 530627f7eb2Smrg else if (digits[i] != '0') 531627f7eb2Smrg break; 532627f7eb2Smrg } 533627f7eb2Smrg 534627f7eb2Smrg /* To format properly, we need to know if the rounded result is zero and if 535627f7eb2Smrg so, we set the zero_flag which may have been already set for 536627f7eb2Smrg actual zero. */ 537627f7eb2Smrg if (i == ndigits + hasdot) 538627f7eb2Smrg { 539627f7eb2Smrg zero_flag = true; 540627f7eb2Smrg /* The output is zero, so set the sign according to the sign bit unless 541627f7eb2Smrg -fno-sign-zero was specified. */ 542627f7eb2Smrg if (compile_options.sign_zero == 1) 543627f7eb2Smrg sign = calculate_sign (dtp, sign_bit); 544627f7eb2Smrg else 545627f7eb2Smrg sign = calculate_sign (dtp, 0); 546627f7eb2Smrg } 547627f7eb2Smrg 548627f7eb2Smrg /* Pick a field size if none was specified, taking into account small 549627f7eb2Smrg values that may have been rounded to zero. */ 550627f7eb2Smrg if (w <= 0) 551627f7eb2Smrg { 552627f7eb2Smrg if (zero_flag) 553627f7eb2Smrg w = d + (sign != S_NONE ? 2 : 1) + (d == 0 ? 1 : 0); 554627f7eb2Smrg else 555627f7eb2Smrg { 556627f7eb2Smrg w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1); 557627f7eb2Smrg w = w == 1 ? 2 : w; 558627f7eb2Smrg } 559627f7eb2Smrg } 560627f7eb2Smrg 561627f7eb2Smrg /* Work out how much padding is needed. */ 562627f7eb2Smrg nblanks = w - (nbefore + nzero + nafter + edigits + 1); 563627f7eb2Smrg if (sign != S_NONE) 564627f7eb2Smrg nblanks--; 565627f7eb2Smrg 566627f7eb2Smrg /* See if we have space for a zero before the decimal point. */ 567627f7eb2Smrg if (nbefore == 0 && nblanks > 0) 568627f7eb2Smrg { 569627f7eb2Smrg leadzero = 1; 570627f7eb2Smrg nblanks--; 571627f7eb2Smrg } 572627f7eb2Smrg else 573627f7eb2Smrg leadzero = 0; 574627f7eb2Smrg 575627f7eb2Smrg if (dtp->u.p.g0_no_blanks) 576627f7eb2Smrg { 577627f7eb2Smrg w -= nblanks; 578627f7eb2Smrg nblanks = 0; 579627f7eb2Smrg } 580627f7eb2Smrg 581627f7eb2Smrg /* Create the final float string. */ 582627f7eb2Smrg *len = w + npad; 583627f7eb2Smrg put = result; 584627f7eb2Smrg 585627f7eb2Smrg /* Check the value fits in the specified field width. */ 586627f7eb2Smrg if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE)) 587627f7eb2Smrg { 588627f7eb2Smrg star_fill (put, *len); 589627f7eb2Smrg return; 590627f7eb2Smrg } 591627f7eb2Smrg 592627f7eb2Smrg /* Pad to full field width. */ 593627f7eb2Smrg if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank) 594627f7eb2Smrg { 595627f7eb2Smrg memset (put, ' ', nblanks); 596627f7eb2Smrg put += nblanks; 597627f7eb2Smrg } 598627f7eb2Smrg 599627f7eb2Smrg /* Set the initial sign (if any). */ 600627f7eb2Smrg if (sign == S_PLUS) 601627f7eb2Smrg *(put++) = '+'; 602627f7eb2Smrg else if (sign == S_MINUS) 603627f7eb2Smrg *(put++) = '-'; 604627f7eb2Smrg 605627f7eb2Smrg /* Set an optional leading zero. */ 606627f7eb2Smrg if (leadzero) 607627f7eb2Smrg *(put++) = '0'; 608627f7eb2Smrg 609627f7eb2Smrg /* Set the part before the decimal point, padding with zeros. */ 610627f7eb2Smrg if (nbefore > 0) 611627f7eb2Smrg { 612627f7eb2Smrg if (nbefore > ndigits) 613627f7eb2Smrg { 614627f7eb2Smrg i = ndigits; 615627f7eb2Smrg memcpy (put, digits, i); 616627f7eb2Smrg ndigits = 0; 617627f7eb2Smrg while (i < nbefore) 618627f7eb2Smrg put[i++] = '0'; 619627f7eb2Smrg } 620627f7eb2Smrg else 621627f7eb2Smrg { 622627f7eb2Smrg i = nbefore; 623627f7eb2Smrg memcpy (put, digits, i); 624627f7eb2Smrg ndigits -= i; 625627f7eb2Smrg } 626627f7eb2Smrg 627627f7eb2Smrg digits += i; 628627f7eb2Smrg put += nbefore; 629627f7eb2Smrg } 630627f7eb2Smrg 631627f7eb2Smrg /* Set the decimal point. */ 632627f7eb2Smrg *(put++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ','; 633627f7eb2Smrg if (ft == FMT_F 634627f7eb2Smrg && (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED 635627f7eb2Smrg || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED)) 636627f7eb2Smrg digits++; 637627f7eb2Smrg 638627f7eb2Smrg /* Set leading zeros after the decimal point. */ 639627f7eb2Smrg if (nzero > 0) 640627f7eb2Smrg { 641627f7eb2Smrg for (i = 0; i < nzero; i++) 642627f7eb2Smrg *(put++) = '0'; 643627f7eb2Smrg } 644627f7eb2Smrg 645627f7eb2Smrg /* Set digits after the decimal point, padding with zeros. */ 646627f7eb2Smrg if (ndigits >= 0 && nafter > 0) 647627f7eb2Smrg { 648627f7eb2Smrg if (nafter > ndigits) 649627f7eb2Smrg i = ndigits; 650627f7eb2Smrg else 651627f7eb2Smrg i = nafter; 652627f7eb2Smrg 653627f7eb2Smrg if (i > 0) 654627f7eb2Smrg memcpy (put, digits, i); 655627f7eb2Smrg while (i < nafter) 656627f7eb2Smrg put[i++] = '0'; 657627f7eb2Smrg 658627f7eb2Smrg digits += i; 659627f7eb2Smrg ndigits -= i; 660627f7eb2Smrg put += nafter; 661627f7eb2Smrg } 662627f7eb2Smrg 663627f7eb2Smrg /* Set the exponent. */ 664627f7eb2Smrg if (expchar && !(dtp->u.p.g0_no_blanks && e == 0)) 665627f7eb2Smrg { 666627f7eb2Smrg if (expchar != ' ') 667627f7eb2Smrg { 668627f7eb2Smrg *(put++) = expchar; 669627f7eb2Smrg edigits--; 670627f7eb2Smrg } 671627f7eb2Smrg snprintf (buffer, size, "%+0*d", edigits, e); 672627f7eb2Smrg memcpy (put, buffer, edigits); 673627f7eb2Smrg put += edigits; 674627f7eb2Smrg } 675627f7eb2Smrg 676627f7eb2Smrg if (dtp->u.p.no_leading_blank) 677627f7eb2Smrg { 678627f7eb2Smrg memset (put , ' ' , nblanks); 679627f7eb2Smrg dtp->u.p.no_leading_blank = 0; 680627f7eb2Smrg put += nblanks; 681627f7eb2Smrg } 682627f7eb2Smrg 683627f7eb2Smrg if (npad > 0 && !dtp->u.p.g0_no_blanks) 684627f7eb2Smrg { 685627f7eb2Smrg memset (put , ' ' , npad); 686627f7eb2Smrg put += npad; 687627f7eb2Smrg } 688627f7eb2Smrg 689627f7eb2Smrg /* NULL terminate the string. */ 690627f7eb2Smrg *put = '\0'; 691627f7eb2Smrg 692627f7eb2Smrg return; 693627f7eb2Smrg} 694627f7eb2Smrg 695627f7eb2Smrg 696627f7eb2Smrg/* Write "Infinite" or "Nan" as appropriate for the given format. */ 697627f7eb2Smrg 698627f7eb2Smrgstatic void 699627f7eb2Smrgbuild_infnan_string (st_parameter_dt *dtp, const fnode *f, int isnan_flag, 700627f7eb2Smrg int sign_bit, char *p, size_t *len) 701627f7eb2Smrg{ 702627f7eb2Smrg char fin; 703627f7eb2Smrg int nb = 0; 704627f7eb2Smrg sign_t sign; 705627f7eb2Smrg int mark; 706627f7eb2Smrg 707627f7eb2Smrg if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z) 708627f7eb2Smrg { 709627f7eb2Smrg sign = calculate_sign (dtp, sign_bit); 710627f7eb2Smrg mark = (sign == S_PLUS || sign == S_MINUS) ? 8 : 7; 711627f7eb2Smrg 712627f7eb2Smrg nb = f->u.real.w; 713627f7eb2Smrg *len = nb; 714627f7eb2Smrg 715627f7eb2Smrg /* If the field width is zero, the processor must select a width 716627f7eb2Smrg not zero. 4 is chosen to allow output of '-Inf' or '+Inf' */ 717627f7eb2Smrg 718627f7eb2Smrg if ((nb == 0) || dtp->u.p.g0_no_blanks) 719627f7eb2Smrg { 720627f7eb2Smrg if (isnan_flag) 721627f7eb2Smrg nb = 3; 722627f7eb2Smrg else 723627f7eb2Smrg nb = (sign == S_PLUS || sign == S_MINUS) ? 4 : 3; 724627f7eb2Smrg *len = nb; 725627f7eb2Smrg } 726627f7eb2Smrg 727627f7eb2Smrg p[*len] = '\0'; 728627f7eb2Smrg if (nb < 3) 729627f7eb2Smrg { 730627f7eb2Smrg memset (p, '*', nb); 731627f7eb2Smrg return; 732627f7eb2Smrg } 733627f7eb2Smrg 734627f7eb2Smrg memset(p, ' ', nb); 735627f7eb2Smrg 736627f7eb2Smrg if (!isnan_flag) 737627f7eb2Smrg { 738627f7eb2Smrg if (sign_bit) 739627f7eb2Smrg { 740627f7eb2Smrg /* If the sign is negative and the width is 3, there is 741627f7eb2Smrg insufficient room to output '-Inf', so output asterisks */ 742627f7eb2Smrg if (nb == 3) 743627f7eb2Smrg { 744627f7eb2Smrg memset (p, '*', nb); 745627f7eb2Smrg return; 746627f7eb2Smrg } 747627f7eb2Smrg /* The negative sign is mandatory */ 748627f7eb2Smrg fin = '-'; 749627f7eb2Smrg } 750627f7eb2Smrg else 751627f7eb2Smrg /* The positive sign is optional, but we output it for 752627f7eb2Smrg consistency */ 753627f7eb2Smrg fin = '+'; 754627f7eb2Smrg 755627f7eb2Smrg if (nb > mark) 756627f7eb2Smrg /* We have room, so output 'Infinity' */ 757627f7eb2Smrg memcpy(p + nb - 8, "Infinity", 8); 758627f7eb2Smrg else 759627f7eb2Smrg /* For the case of width equals 8, there is not enough room 760627f7eb2Smrg for the sign and 'Infinity' so we go with 'Inf' */ 761627f7eb2Smrg memcpy(p + nb - 3, "Inf", 3); 762627f7eb2Smrg 763627f7eb2Smrg if (sign == S_PLUS || sign == S_MINUS) 764627f7eb2Smrg { 765627f7eb2Smrg if (nb < 9 && nb > 3) 766627f7eb2Smrg p[nb - 4] = fin; /* Put the sign in front of Inf */ 767627f7eb2Smrg else if (nb > 8) 768627f7eb2Smrg p[nb - 9] = fin; /* Put the sign in front of Infinity */ 769627f7eb2Smrg } 770627f7eb2Smrg } 771627f7eb2Smrg else 772627f7eb2Smrg memcpy(p + nb - 3, "NaN", 3); 773627f7eb2Smrg } 774627f7eb2Smrg} 775627f7eb2Smrg 776627f7eb2Smrg 777627f7eb2Smrg/* Returns the value of 10**d. */ 778627f7eb2Smrg 779627f7eb2Smrg#define CALCULATE_EXP(x) \ 780627f7eb2Smrgstatic GFC_REAL_ ## x \ 781627f7eb2Smrgcalculate_exp_ ## x (int d)\ 782627f7eb2Smrg{\ 783627f7eb2Smrg int i;\ 784627f7eb2Smrg GFC_REAL_ ## x r = 1.0;\ 785627f7eb2Smrg for (i = 0; i< (d >= 0 ? d : -d); i++)\ 786627f7eb2Smrg r *= 10;\ 787627f7eb2Smrg r = (d >= 0) ? r : 1.0 / r;\ 788627f7eb2Smrg return r;\ 789627f7eb2Smrg} 790627f7eb2Smrg 791627f7eb2SmrgCALCULATE_EXP(4) 792627f7eb2Smrg 793627f7eb2SmrgCALCULATE_EXP(8) 794627f7eb2Smrg 795627f7eb2Smrg#ifdef HAVE_GFC_REAL_10 796627f7eb2SmrgCALCULATE_EXP(10) 797627f7eb2Smrg#endif 798627f7eb2Smrg 799627f7eb2Smrg#ifdef HAVE_GFC_REAL_16 800627f7eb2SmrgCALCULATE_EXP(16) 801627f7eb2Smrg#endif 802627f7eb2Smrg#undef CALCULATE_EXP 803627f7eb2Smrg 804627f7eb2Smrg 805627f7eb2Smrg/* Define macros to build code for format_float. */ 806627f7eb2Smrg 807627f7eb2Smrg /* Note: Before output_float is called, snprintf is used to print to buffer the 808627f7eb2Smrg number in the format +D.DDDDe+ddd. 809627f7eb2Smrg 810627f7eb2Smrg # The result will always contain a decimal point, even if no 811627f7eb2Smrg digits follow it 812627f7eb2Smrg 813627f7eb2Smrg - The converted value is to be left adjusted on the field boundary 814627f7eb2Smrg 815627f7eb2Smrg + A sign (+ or -) always be placed before a number 816627f7eb2Smrg 817627f7eb2Smrg * prec is used as the precision 818627f7eb2Smrg 819627f7eb2Smrg e format: [-]d.ddde±dd where there is one digit before the 820627f7eb2Smrg decimal-point character and the number of digits after it is 821627f7eb2Smrg equal to the precision. The exponent always contains at least two 822627f7eb2Smrg digits; if the value is zero, the exponent is 00. */ 823627f7eb2Smrg 824627f7eb2Smrg 825627f7eb2Smrg#define TOKENPASTE(x, y) TOKENPASTE2(x, y) 826627f7eb2Smrg#define TOKENPASTE2(x, y) x ## y 827627f7eb2Smrg 828627f7eb2Smrg#define DTOA(suff,prec,val) TOKENPASTE(DTOA2,suff)(prec,val) 829627f7eb2Smrg 830627f7eb2Smrg#define DTOA2(prec,val) \ 831627f7eb2Smrgsnprintf (buffer, size, "%+-#.*e", (prec), (val)) 832627f7eb2Smrg 833627f7eb2Smrg#define DTOA2L(prec,val) \ 834627f7eb2Smrgsnprintf (buffer, size, "%+-#.*Le", (prec), (val)) 835627f7eb2Smrg 836627f7eb2Smrg 837627f7eb2Smrg#if defined(GFC_REAL_16_IS_FLOAT128) 838627f7eb2Smrg#define DTOA2Q(prec,val) \ 839627f7eb2Smrgquadmath_snprintf (buffer, size, "%+-#.*Qe", (prec), (val)) 840627f7eb2Smrg#endif 841627f7eb2Smrg 842627f7eb2Smrg#define FDTOA(suff,prec,val) TOKENPASTE(FDTOA2,suff)(prec,val) 843627f7eb2Smrg 844627f7eb2Smrg/* For F format, we print to the buffer with f format. */ 845627f7eb2Smrg#define FDTOA2(prec,val) \ 846627f7eb2Smrgsnprintf (buffer, size, "%+-#.*f", (prec), (val)) 847627f7eb2Smrg 848627f7eb2Smrg#define FDTOA2L(prec,val) \ 849627f7eb2Smrgsnprintf (buffer, size, "%+-#.*Lf", (prec), (val)) 850627f7eb2Smrg 851627f7eb2Smrg 852627f7eb2Smrg#if defined(GFC_REAL_16_IS_FLOAT128) 853627f7eb2Smrg#define FDTOA2Q(prec,val) \ 854627f7eb2Smrgquadmath_snprintf (buffer, size, "%+-#.*Qf", \ 855627f7eb2Smrg (prec), (val)) 856627f7eb2Smrg#endif 857627f7eb2Smrg 858627f7eb2Smrg 859627f7eb2Smrg/* EN format is tricky since the number of significant digits depends 860627f7eb2Smrg on the magnitude. Solve it by first printing a temporary value and 861627f7eb2Smrg figure out the number of significant digits from the printed 862627f7eb2Smrg exponent. Values y, 0.95*10.0**e <= y <10.0**e, are rounded to 863627f7eb2Smrg 10.0**e even when the final result will not be rounded to 10.0**e. 864627f7eb2Smrg For these values the exponent returned by atoi has to be decremented 865627f7eb2Smrg by one. The values y in the ranges 866627f7eb2Smrg (1000.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*(n+1)) 867627f7eb2Smrg (100.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+2) 868627f7eb2Smrg (10.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+1) 869627f7eb2Smrg are correctly rounded respectively to 1.0...0*10.0*(3*(n+1)), 870627f7eb2Smrg 100.0...0*10.0*(3*n), and 10.0...0*10.0*(3*n), where 0...0 871627f7eb2Smrg represents d zeroes, by the lines 279 to 297. */ 872627f7eb2Smrg#define EN_PREC(x,y)\ 873627f7eb2Smrg{\ 874627f7eb2Smrg volatile GFC_REAL_ ## x tmp, one = 1.0;\ 875627f7eb2Smrg tmp = * (GFC_REAL_ ## x *)source;\ 876627f7eb2Smrg if (isfinite (tmp))\ 877627f7eb2Smrg {\ 878627f7eb2Smrg nprinted = DTOA(y,0,tmp);\ 879627f7eb2Smrg int e = atoi (&buffer[4]);\ 880627f7eb2Smrg if (buffer[1] == '1')\ 881627f7eb2Smrg {\ 882627f7eb2Smrg tmp = (calculate_exp_ ## x (-e)) * tmp;\ 883627f7eb2Smrg tmp = one - (tmp < 0 ? -tmp : tmp);\ 884627f7eb2Smrg if (tmp > 0)\ 885627f7eb2Smrg e = e - 1;\ 886627f7eb2Smrg }\ 887627f7eb2Smrg nbefore = e%3;\ 888627f7eb2Smrg if (nbefore < 0)\ 889627f7eb2Smrg nbefore = 3 + nbefore;\ 890627f7eb2Smrg }\ 891627f7eb2Smrg else\ 892627f7eb2Smrg nprinted = -1;\ 893627f7eb2Smrg}\ 894627f7eb2Smrg 895627f7eb2Smrgstatic int 896627f7eb2Smrgdetermine_en_precision (st_parameter_dt *dtp, const fnode *f, 897627f7eb2Smrg const char *source, int len) 898627f7eb2Smrg{ 899627f7eb2Smrg int nprinted; 900627f7eb2Smrg char buffer[10]; 901627f7eb2Smrg const size_t size = 10; 902627f7eb2Smrg int nbefore; /* digits before decimal point - 1. */ 903627f7eb2Smrg 904627f7eb2Smrg switch (len) 905627f7eb2Smrg { 906627f7eb2Smrg case 4: 907627f7eb2Smrg EN_PREC(4,) 908627f7eb2Smrg break; 909627f7eb2Smrg 910627f7eb2Smrg case 8: 911627f7eb2Smrg EN_PREC(8,) 912627f7eb2Smrg break; 913627f7eb2Smrg 914627f7eb2Smrg#ifdef HAVE_GFC_REAL_10 915627f7eb2Smrg case 10: 916627f7eb2Smrg EN_PREC(10,L) 917627f7eb2Smrg break; 918627f7eb2Smrg#endif 919627f7eb2Smrg#ifdef HAVE_GFC_REAL_16 920627f7eb2Smrg case 16: 921627f7eb2Smrg# ifdef GFC_REAL_16_IS_FLOAT128 922627f7eb2Smrg EN_PREC(16,Q) 923627f7eb2Smrg# else 924627f7eb2Smrg EN_PREC(16,L) 925627f7eb2Smrg# endif 926627f7eb2Smrg break; 927627f7eb2Smrg#endif 928627f7eb2Smrg default: 929627f7eb2Smrg internal_error (NULL, "bad real kind"); 930627f7eb2Smrg } 931627f7eb2Smrg 932627f7eb2Smrg if (nprinted == -1) 933627f7eb2Smrg return -1; 934627f7eb2Smrg 935627f7eb2Smrg int prec = f->u.real.d + nbefore; 936627f7eb2Smrg if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED 937627f7eb2Smrg && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED) 938627f7eb2Smrg prec += 2 * len + 4; 939627f7eb2Smrg return prec; 940627f7eb2Smrg} 941627f7eb2Smrg 942627f7eb2Smrg 943627f7eb2Smrg/* Generate corresponding I/O format. and output. 944627f7eb2Smrg The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran 945627f7eb2Smrg LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is: 946627f7eb2Smrg 947627f7eb2Smrg Data Magnitude Equivalent Conversion 948627f7eb2Smrg 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee] 949627f7eb2Smrg m = 0 F(w-n).(d-1), n' ' 950627f7eb2Smrg 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' ' 951627f7eb2Smrg 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' ' 952627f7eb2Smrg 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' ' 953627f7eb2Smrg ................ .......... 954627f7eb2Smrg 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ') 955627f7eb2Smrg m >= 10**d-0.5 Ew.d[Ee] 956627f7eb2Smrg 957627f7eb2Smrg notes: for Gw.d , n' ' means 4 blanks 958627f7eb2Smrg for Gw.dEe, n' ' means e+2 blanks 959627f7eb2Smrg for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2 960627f7eb2Smrg the asm volatile is required for 32-bit x86 platforms. */ 961627f7eb2Smrg#define FORMAT_FLOAT(x,y)\ 962627f7eb2Smrg{\ 963627f7eb2Smrg int npad = 0;\ 964627f7eb2Smrg GFC_REAL_ ## x m;\ 965627f7eb2Smrg m = * (GFC_REAL_ ## x *)source;\ 966627f7eb2Smrg sign_bit = signbit (m);\ 967627f7eb2Smrg if (!isfinite (m))\ 968627f7eb2Smrg { \ 969627f7eb2Smrg build_infnan_string (dtp, f, isnan (m), sign_bit, result, res_len);\ 970627f7eb2Smrg return;\ 971627f7eb2Smrg }\ 972627f7eb2Smrg m = sign_bit ? -m : m;\ 973627f7eb2Smrg zero_flag = (m == 0.0);\ 974627f7eb2Smrg if (f->format == FMT_G)\ 975627f7eb2Smrg {\ 976627f7eb2Smrg int e = f->u.real.e;\ 977627f7eb2Smrg int d = f->u.real.d;\ 978627f7eb2Smrg int w = f->u.real.w;\ 979627f7eb2Smrg fnode newf;\ 980627f7eb2Smrg GFC_REAL_ ## x exp_d, r = 0.5, r_sc;\ 981627f7eb2Smrg int low, high, mid;\ 982627f7eb2Smrg int ubound, lbound;\ 983627f7eb2Smrg int save_scale_factor;\ 984627f7eb2Smrg volatile GFC_REAL_ ## x temp;\ 985627f7eb2Smrg save_scale_factor = dtp->u.p.scale_factor;\ 986*4c3eb207Smrg if (w == DEFAULT_WIDTH)\ 987*4c3eb207Smrg {\ 988*4c3eb207Smrg w = default_width;\ 989*4c3eb207Smrg d = precision;\ 990*4c3eb207Smrg }\ 991*4c3eb207Smrg /* The switch between FMT_E and FMT_F is based on the absolute value. \ 992*4c3eb207Smrg Set r=0 for rounding toward zero and r = 1 otherwise. \ 993*4c3eb207Smrg If (exp_d - m) == 1 there is no rounding needed. */\ 994627f7eb2Smrg switch (dtp->u.p.current_unit->round_status)\ 995627f7eb2Smrg {\ 996627f7eb2Smrg case ROUND_ZERO:\ 997*4c3eb207Smrg r = 0.0;\ 998627f7eb2Smrg break;\ 999627f7eb2Smrg case ROUND_UP:\ 1000*4c3eb207Smrg r = sign_bit ? 0.0 : 1.0;\ 1001627f7eb2Smrg break;\ 1002627f7eb2Smrg case ROUND_DOWN:\ 1003*4c3eb207Smrg r = sign_bit ? 1.0 : 0.0;\ 1004627f7eb2Smrg break;\ 1005627f7eb2Smrg default:\ 1006627f7eb2Smrg break;\ 1007627f7eb2Smrg }\ 1008627f7eb2Smrg exp_d = calculate_exp_ ## x (d);\ 1009627f7eb2Smrg r_sc = (1 - r / exp_d);\ 1010627f7eb2Smrg temp = 0.1 * r_sc;\ 1011*4c3eb207Smrg if ((m > 0.0 && ((m < temp) || (r < 1 && r >= (exp_d - m))\ 1012*4c3eb207Smrg || (r == 1 && 1 > (exp_d - m))))\ 1013627f7eb2Smrg || ((m == 0.0) && !(compile_options.allow_std\ 1014627f7eb2Smrg & (GFC_STD_F2003 | GFC_STD_F2008)))\ 1015627f7eb2Smrg || d == 0)\ 1016627f7eb2Smrg { \ 1017627f7eb2Smrg newf.format = FMT_E;\ 1018627f7eb2Smrg newf.u.real.w = w;\ 1019627f7eb2Smrg newf.u.real.d = d - comp_d;\ 1020627f7eb2Smrg newf.u.real.e = e;\ 1021627f7eb2Smrg npad = 0;\ 1022627f7eb2Smrg precision = determine_precision (dtp, &newf, x);\ 1023627f7eb2Smrg nprinted = DTOA(y,precision,m);\ 1024627f7eb2Smrg }\ 1025627f7eb2Smrg else \ 1026627f7eb2Smrg {\ 1027627f7eb2Smrg mid = 0;\ 1028627f7eb2Smrg low = 0;\ 1029627f7eb2Smrg high = d + 1;\ 1030627f7eb2Smrg lbound = 0;\ 1031627f7eb2Smrg ubound = d + 1;\ 1032627f7eb2Smrg while (low <= high)\ 1033627f7eb2Smrg {\ 1034627f7eb2Smrg mid = (low + high) / 2;\ 1035627f7eb2Smrg temp = (calculate_exp_ ## x (mid - 1) * r_sc);\ 1036627f7eb2Smrg if (m < temp)\ 1037627f7eb2Smrg { \ 1038627f7eb2Smrg ubound = mid;\ 1039627f7eb2Smrg if (ubound == lbound + 1)\ 1040627f7eb2Smrg break;\ 1041627f7eb2Smrg high = mid - 1;\ 1042627f7eb2Smrg }\ 1043627f7eb2Smrg else if (m > temp)\ 1044627f7eb2Smrg { \ 1045627f7eb2Smrg lbound = mid;\ 1046627f7eb2Smrg if (ubound == lbound + 1)\ 1047627f7eb2Smrg { \ 1048627f7eb2Smrg mid ++;\ 1049627f7eb2Smrg break;\ 1050627f7eb2Smrg }\ 1051627f7eb2Smrg low = mid + 1;\ 1052627f7eb2Smrg }\ 1053627f7eb2Smrg else\ 1054627f7eb2Smrg {\ 1055627f7eb2Smrg mid++;\ 1056627f7eb2Smrg break;\ 1057627f7eb2Smrg }\ 1058627f7eb2Smrg }\ 1059627f7eb2Smrg npad = e <= 0 ? 4 : e + 2;\ 1060627f7eb2Smrg npad = npad >= w ? w - 1 : npad;\ 1061627f7eb2Smrg npad = dtp->u.p.g0_no_blanks ? 0 : npad;\ 1062627f7eb2Smrg newf.format = FMT_F;\ 1063627f7eb2Smrg newf.u.real.w = w - npad;\ 1064627f7eb2Smrg newf.u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\ 1065627f7eb2Smrg dtp->u.p.scale_factor = 0;\ 1066627f7eb2Smrg precision = determine_precision (dtp, &newf, x);\ 1067627f7eb2Smrg nprinted = FDTOA(y,precision,m);\ 1068627f7eb2Smrg }\ 1069627f7eb2Smrg build_float_string (dtp, &newf, buffer, size, nprinted, precision,\ 1070*4c3eb207Smrg sign_bit, zero_flag, npad, default_width,\ 1071*4c3eb207Smrg result, res_len);\ 1072627f7eb2Smrg dtp->u.p.scale_factor = save_scale_factor;\ 1073627f7eb2Smrg }\ 1074627f7eb2Smrg else\ 1075627f7eb2Smrg {\ 1076627f7eb2Smrg if (f->format == FMT_F)\ 1077627f7eb2Smrg nprinted = FDTOA(y,precision,m);\ 1078627f7eb2Smrg else\ 1079627f7eb2Smrg nprinted = DTOA(y,precision,m);\ 1080627f7eb2Smrg build_float_string (dtp, f, buffer, size, nprinted, precision,\ 1081*4c3eb207Smrg sign_bit, zero_flag, npad, default_width,\ 1082*4c3eb207Smrg result, res_len);\ 1083627f7eb2Smrg }\ 1084627f7eb2Smrg}\ 1085627f7eb2Smrg 1086627f7eb2Smrg/* Output a real number according to its format. */ 1087627f7eb2Smrg 1088627f7eb2Smrg 1089627f7eb2Smrgstatic void 1090627f7eb2Smrgget_float_string (st_parameter_dt *dtp, const fnode *f, const char *source, 1091627f7eb2Smrg int kind, int comp_d, char *buffer, int precision, 1092627f7eb2Smrg size_t size, char *result, size_t *res_len) 1093627f7eb2Smrg{ 1094627f7eb2Smrg int sign_bit, nprinted; 1095627f7eb2Smrg bool zero_flag; 1096*4c3eb207Smrg int default_width = 0; 1097*4c3eb207Smrg 1098*4c3eb207Smrg if (f->u.real.w == DEFAULT_WIDTH) 1099*4c3eb207Smrg /* This codepath can only be reached with -fdec-format-defaults. The default 1100*4c3eb207Smrg * values are based on those used in the Oracle Fortran compiler. 1101*4c3eb207Smrg */ 1102*4c3eb207Smrg { 1103*4c3eb207Smrg default_width = default_width_for_float (kind); 1104*4c3eb207Smrg precision = default_precision_for_float (kind); 1105*4c3eb207Smrg } 1106627f7eb2Smrg 1107627f7eb2Smrg switch (kind) 1108627f7eb2Smrg { 1109627f7eb2Smrg case 4: 1110627f7eb2Smrg FORMAT_FLOAT(4,) 1111627f7eb2Smrg break; 1112627f7eb2Smrg 1113627f7eb2Smrg case 8: 1114627f7eb2Smrg FORMAT_FLOAT(8,) 1115627f7eb2Smrg break; 1116627f7eb2Smrg 1117627f7eb2Smrg#ifdef HAVE_GFC_REAL_10 1118627f7eb2Smrg case 10: 1119627f7eb2Smrg FORMAT_FLOAT(10,L) 1120627f7eb2Smrg break; 1121627f7eb2Smrg#endif 1122627f7eb2Smrg#ifdef HAVE_GFC_REAL_16 1123627f7eb2Smrg case 16: 1124627f7eb2Smrg# ifdef GFC_REAL_16_IS_FLOAT128 1125627f7eb2Smrg FORMAT_FLOAT(16,Q) 1126627f7eb2Smrg# else 1127627f7eb2Smrg FORMAT_FLOAT(16,L) 1128627f7eb2Smrg# endif 1129627f7eb2Smrg break; 1130627f7eb2Smrg#endif 1131627f7eb2Smrg default: 1132627f7eb2Smrg internal_error (NULL, "bad real kind"); 1133627f7eb2Smrg } 1134627f7eb2Smrg return; 1135627f7eb2Smrg} 1136