quad-conversion.c

     
   1  //! @file quad-conversion.c
   2  //!
   3  //! @author (see below)
   4  //!
   5  //! @section Copyright
   6  //!
   7  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   8  //! Copyright 2001-2023 J. Marcel van der Veer [algol68g@xs4all.nl].
   9  //!
  10  //! @section License
  11  //!
  12  //! This program is free software; you can redistribute it and/or modify it 
  13  //! under the terms of the GNU General Public License as published by the 
  14  //! Free Software Foundation; either version 3 of the License, or 
  15  //! (at your option) any later version.
  16  //!
  17  //! This program is distributed in the hope that it will be useful, but 
  18  //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  19  //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
  20  //! more details. You should have received a copy of the GNU General Public 
  21  //! License along with this program. If not, see [http://www.gnu.org/licenses/].
  22  
  23  //! @section Synopsis
  24  //!
  25  //! Fixed precision LONG LONG REAL/COMPLEX conversions.
  26  
  27  // This code is based in part on the HPA Library, a branch of the CCMath library.
  28  // The CCMath library and derived HPA Library are free software under the terms 
  29  // of the GNU Lesser General Public License version 2.1 or any later version.
  30  //
  31  // Sources:
  32  //   [https://directory.fsf.org/wiki/HPAlib]
  33  //   [http://download-mirror.savannah.gnu.org/releases/hpalib/]
  34  //   [http://savannah.nongnu.org/projects/hpalib]
  35  //
  36  //   Copyright 2000 Daniel A. Atkinson  [DanAtk@aol.com]
  37  //   Copyright 2004 Ivano Primi         [ivprimi@libero.it]  
  38  //   Copyright 2023 Marcel van der Veer [algol68g@xs4all.nl] - A68G version.
  39  
  40  #include "a68g.h"
  41  
  42  #if (A68_LEVEL >= 3)
  43  
  44  #include "a68g-quad.h"
  45  
  46  // Conversion.
  47  
  48  //! @brief int_to_quad_real
  49  
  50  QUAD_T int_to_quad_real (int n)
  51  {
  52    REAL32 pe;
  53    unt_2 *pc, e;
  54    unt k, h;
  55    memset (pe, 0, sizeof (pe));
  56    k = ABS (n);
  57    pc = (unt_2 *) &k;
  58    if (n == 0) {
  59      return *(QUAD_T *) pe;
  60    }
  61  
  62  #if (__BYTE_ORDER == __LITTLE_ENDIAN)
  63    pe[1] = *(pc + 1);
  64    pe[2] = *pc;
  65  #else
  66    pe[1] = *pc;
  67    pe[2] = *(pc + 1);
  68  #endif
  69  
  70    for (e = 0, h = 1; h <= k && e < ((8 * sizeof (unt)) - 1); h <<= 1, ++e);
  71    if (h <= k) {
  72      e += 1;
  73    }
  74    *pe = QUAD_REAL_BIAS + e - 1;
  75    if (n < 0) {
  76      *pe |= QUAD_REAL_M_SIGN;
  77    }
  78    lshift_quad_real ((8 * sizeof (unt)) - e, pe + 1, FLT256_LEN);
  79    return *(QUAD_T *) pe;
  80  }
  81  
  82  //! @brief quad_real_to_real
  83  
  84  REAL_T quad_real_to_real (QUAD_T s)
  85  {
  86    union {unt_2 pe[4]; REAL_T d;} v;
  87    unt_2 *pc, u;
  88    int_2 i, e;
  89    pc = (unt_2 *) &QV (s);
  90    u = *pc & QUAD_REAL_M_SIGN;
  91    e = (*pc & QUAD_REAL_M_EXP) - QUAD_REAL_DBL_BIAS;
  92    if (e >= QUAD_REAL_DBL_MAX) {
  93      return (!u ? DBL_MAX : -DBL_MAX);
  94    }
  95    if (e <= 0) {
  96      return 0.;
  97    }
  98    for (i = 0; i < 4; v.pe[i] = *++pc, i++);
  99    v.pe[0] &= QUAD_REAL_M_EXP;
 100    rshift_quad_real (QUAD_REAL_DBL_LEX - 1, v.pe, 4);
 101    v.pe[0] |= (e << (16 - QUAD_REAL_DBL_LEX));
 102    v.pe[0] |= u;
 103  #if (__BYTE_ORDER == __LITTLE_ENDIAN)
 104    u = v.pe[3];
 105    v.pe[3] = v.pe[0];
 106    v.pe[0] = u;
 107    u = v.pe[2];
 108    v.pe[2] = v.pe[1];
 109    v.pe[1] = u;
 110  #endif
 111    return v.d;
 112  }
 113  
 114  //! @brief real_to_quad_real
 115  
 116  QUAD_T real_to_quad_real (REAL_T y)
 117  {
 118    REAL32 pe;
 119    unt_2 *pc, u;
 120    int_2 i, e;
 121    if (y < DBL_MIN && y > -DBL_MIN) {
 122      return QUAD_REAL_ZERO;
 123    }
 124    memset (pe, 0, sizeof (pe));
 125    pc = (unt_2 *) &y;
 126  #if (__BYTE_ORDER == __LITTLE_ENDIAN)
 127    pc += 3;
 128  #endif
 129    u = *pc & QUAD_REAL_M_SIGN;
 130    e = QUAD_REAL_DBL_BIAS + ((*pc & QUAD_REAL_M_EXP) >> (16 - QUAD_REAL_DBL_LEX));
 131  #if (__BYTE_ORDER == __LITTLE_ENDIAN)
 132    for (i = 1; i < 5; pe[i] = *pc--, i++);
 133  #else
 134    for (i = 1; i < 5; pe[i] = *pc++, i++);
 135  #endif
 136    pc = pe + 1;
 137    lshift_quad_real (QUAD_REAL_DBL_LEX - 1, pc, 4);
 138    *pc |= QUAD_REAL_M_SIGN;
 139    *pe = e;
 140    *pe |= u;
 141    return *(QUAD_T *) pe;
 142  }
 143  
 144  //! @brief double_real_to_quad_real
 145  
 146  QUAD_T double_real_to_quad_real (DOUBLE_T x)
 147  {
 148    if (x == 0.0q) {
 149      return QUAD_REAL_ZERO;
 150    }
 151    int sinf = isinfq (x);
 152    if (sinf == 1) {
 153      return QUAD_REAL_PINF;
 154    } else if (sinf == -1) {
 155      return QUAD_REAL_MINF;
 156    }
 157    if (isnanq (x)) {
 158      return QUAD_REAL_NAN;
 159    }
 160    QUAD_T z = QUAD_REAL_ZERO;
 161    unt_2 *y = (unt_2 *) &x;
 162    for (unt i = 0; i < 8; i++) {
 163  #if (__BYTE_ORDER == __LITTLE_ENDIAN)
 164      QV (z)[i] = y[7 - i];
 165  #else
 166      QV (z)[i] = y[i];
 167  #endif
 168    }
 169  // double_real skips the default first bit, HPA lib does not.
 170    unt_2 cy = 0x8000;
 171    for (unt i = 1; i < 8; i++) {
 172      if (QV (z)[i] & 0x1) {
 173        QV (z)[i] = (QV (z)[i] >> 1) | cy;
 174        cy = 0x8000;
 175      } else {
 176        QV (z)[i] = (QV (z)[i] >> 1) | cy;
 177        cy = 0x0;
 178      }
 179    }
 180    QV (z)[8] |= cy;
 181    return z;
 182  }
 183  
 184  DOUBLE_T quad_real_to_double_real (QUAD_T x)
 185  {
 186    REAL16 y; REAL32 z;
 187    int i;
 188    memcpy (z, x.value, sizeof (QUAD_T));
 189  // Catch NaN, +-Inf is handled correctly.
 190    if (isNaN_quad_real (&x)) {
 191      z[0] = 0x7fff;
 192      z[1] = 0xffff;
 193    }
 194  // double_real skips the default first bit, HPA lib does not.
 195    unt_2 cy = (z[8] & 0x8000 ? 0x1 : 0x0);
 196    for (i = 7; i > 0; i--) {
 197      if (z[i] & 0x8000) {
 198        z[i] = (z[i] << 1) | cy;
 199        cy = 0x1;
 200      } else {
 201        z[i] = (z[i] << 1) | cy;
 202        cy = 0x0;
 203      }
 204    }
 205    for (i = 0; i < 8; i++) {
 206  #if (__BYTE_ORDER == __LITTLE_ENDIAN)
 207      y[i] = z[7 - i];
 208  #else
 209      y[i] = z[i];
 210  #endif
 211    }
 212  // Avoid 'dereferencing type-punned pointer will break strict-aliasing rules'
 213    DOUBLE_T u;
 214    memcpy (&u, &y[0], sizeof (DOUBLE_T));
 215    return u;
 216  }
 217  
 218  //! @brief string_to_quad_real
 219  
 220  QUAD_T string_to_quad_real (const char *q, char **endptr)
 221  {
 222  #define QUAD_UPB (QUAD_REAL_MAX_10EX + 100)
 223    QUAD_T s, f;
 224    REAL32 pc;
 225    unt_2 *pn, *pf, *pa, *pb;
 226    unt_2 sfg, ibex, fbex;
 227    unt n;
 228    int j;
 229    int idex = 0, fdex = 0, c, m;
 230    int_2 noip, nofp;
 231    const char *ptr;
 232    pn = (unt_2 *) &QV (s);
 233    pf = (unt_2 *) &QV (f);
 234    for (j = 0; j <= FLT256_LEN; pn[j] = pf[j] = pc[j] = 0, ++j);
 235    sfg = 0;
 236    m = FLT256_LEN + 1;
 237    if (endptr != NULL) {
 238      *endptr = (char *) q;
 239    }
 240  // Skip leading white space
 241    while ((isspace (*q))) {
 242      q++;
 243    }
 244  // Sign 
 245    if (*q == '+') {
 246      ++q;
 247    } else if (*q == '-') {
 248      sfg = 0x8000;
 249      ++q;
 250    }
 251  // Integer part 
 252    for (ptr = q; (c = *q - '0') >= 0 && c <= 9; ++q) {
 253      if (pn[0]) {
 254        ++idex;
 255      } else {
 256        lshift_quad_real (1, pn, m);
 257        for (j = 0; j < m; ++j) {
 258          pc[j] = pn[j];
 259        }
 260        lshift_quad_real (2, pn, m);
 261        for (n = (unt) c, pa = pn + FLT256_LEN, pb = pc + FLT256_LEN; pa >= pn; pa--, pb--) {
 262          n += *pa + *pb;
 263          *pa = n;
 264          n >>= 16;
 265        }
 266      }
 267    }
 268    for (j = 0; j < m && pn[j] == 0; ++j);
 269    if (j == m) {
 270      ibex = 0;
 271    } else {
 272      ibex = QUAD_REAL_BIAS + QUAD_REAL_MAX_P - 1;
 273      if (j != 0) {
 274        j <<= 4;
 275        ibex -= j;
 276        lshift_quad_real (j, pn, m);
 277      }
 278      while (pn[0]) {
 279        rshift_quad_real (1, pn, m);
 280        ++ibex;
 281      }
 282      pn[0] = ibex | sfg;
 283    }
 284    noip = ptr == q;
 285  // End Integer part 
 286    if (*q == '.') {
 287  // Fractionary part 
 288      for (j = 0; j <= FLT256_LEN; ++j) {
 289        pc[j] = 0;
 290      }
 291      for (ptr = ++q; (c = *q - '0') >= 0 && c <= 9 && pf[0] == 0; --fdex, ++q) {
 292        lshift_quad_real (1, pf, m);
 293        for (j = 0; j < m; ++j) {
 294          pc[j] = pf[j];
 295        }
 296        lshift_quad_real (2, pf, m);
 297        for (n = (unt) c, pa = pf + FLT256_LEN, pb = pc + FLT256_LEN; pa >= pf; pa--, pb--) {
 298          n += *pa + *pb;
 299          *pa = n;
 300          n >>= 16;
 301        }
 302      }
 303      for (j = 0; j < m && pf[j] == 0; ++j);
 304      if (j == m) {
 305        fbex = 0;
 306      } else {
 307        fbex = QUAD_REAL_BIAS + QUAD_REAL_MAX_P - 1;
 308        if (j != 0) {
 309          j <<= 4;
 310          fbex -= j;
 311          lshift_quad_real (j, pf, m);
 312        }
 313        while (pf[0]) {
 314          rshift_quad_real (1, pf, m);
 315          ++fbex;
 316        }
 317        pf[0] = fbex | sfg;
 318      }
 319      nofp = ptr == q;
 320    } else {
 321      nofp = 1;
 322    }
 323    if (noip && nofp) {
 324      return QUAD_REAL_NAN;
 325    } else {
 326  // Ignore digits beyond precision.
 327      for (; *q >= '0' && *q <= '9'; q++);
 328      if (endptr != NULL) {
 329        *endptr = (char *) q;
 330      }
 331    }
 332  // Exponent 
 333    if (tolower (*q) == 'e' || tolower (*q) == 'q') {
 334      ++q;
 335      sfg = 0;
 336      if (*q == '+') {
 337        ++q;
 338      } else if (*q == '-') {
 339        sfg = 1;
 340        ++q;
 341      }
 342      for (ptr = q, j = 0; (c = *q - '0') >= 0 && c <= 9 && j <= QUAD_UPB; ++q) {
 343        j <<= 1;
 344        m = j;
 345        j <<= 2;
 346        j += c + m;
 347      }
 348      if (ptr != q && (endptr != 0)) {
 349        *endptr = (char *) q;
 350      }
 351      if (sfg != 0) {
 352        j = -j;
 353      }
 354      idex += j;
 355      fdex += j;
 356    }
 357  // Remark: s and f have the same sign (see above). 
 358    if (idex > QUAD_REAL_MAX_10EX || fdex > QUAD_REAL_MAX_10EX) {
 359      return ((s.value[0] & QUAD_REAL_M_SIGN) ? QUAD_REAL_MINF : QUAD_REAL_PINF);
 360    } else {
 361      if (idex != 0) {
 362        s = mul_quad_real (s, ten_up_quad_real (idex));
 363      }
 364      if (fdex != 0) {
 365        f = mul_quad_real (f, ten_up_quad_real (fdex));
 366      }
 367      return _add_quad_real_ (s, f);
 368    }
 369  #undef QUAD_UPB
 370  }
 371  
 372  //! @brief atox
 373  
 374  QUAD_T atox (const char *q)
 375  {
 376    return string_to_quad_real (q, NULL);
 377  }
 378  
 379  // _scale_ is set by nP in formats.
 380  
 381  int _scale_ = 1;
 382  
 383  //! @brief srecordf
 384  
 385  int srecordf (char *s, const char *format, ...)
 386  {
 387    size_t N = BUFFER_SIZE;
 388    va_list ap;
 389    va_start (ap, format);
 390    int vsnprintf (char *, size_t, const char *, va_list);
 391  // Print in new string, just in case 's' is also an argument!
 392    int M = N + 16; // A bit longer so we trap too long prints.
 393    char *t = malloc (M);
 394    int Np = vsnprintf (t, M, format, ap);
 395    va_end (ap);
 396    if (Np >= N) {
 397      free (t);
 398      QUAD_RTE ("srecordf", "overflow");
 399    } else {
 400      strcpy (s, t);
 401      free (t);
 402    }
 403    return Np;
 404  }
 405  
 406  //! @brief strlcat
 407  
 408  char *strlcat (char *dst, char *src, int len)
 409  {
 410  // Fortran string lengths are len+1, last one is for null.
 411    int avail = len - (int) strlen (dst);
 412    if (avail <= (int) strlen (src)) {
 413      QUAD_RTE ("_strlcat", "overflow");
 414    } else {
 415      strncat (dst, src, avail);
 416    }
 417    dst[len] = '\0';
 418    return dst;
 419  }
 420  
 421  //! @brief plusab
 422  
 423  static char *plusab (char *buf, char c)
 424  {
 425    char z[2];
 426    z[0] = c;
 427    z[1] = '\0';
 428    strlcat (buf, z, BUFFER_SIZE);
 429    return buf;
 430  }
 431  
 432  //! @brief plusto
 433  
 434  static char *plusto (char ch, char *buf)
 435  {
 436    memmove (&buf[1], &buf[0], strlen(buf) + 1);
 437    buf[0] = ch;
 438    return buf;
 439  }
 440  
 441  //! @brief leading_spaces
 442  
 443  static char *leading_spaces (char *buf, int width)
 444  {
 445    if (width > 0) {
 446      int j = ABS (width) - (int) strlen (buf);
 447      while (--j >= 0) {
 448        (void) plusto (' ', buf);
 449      }
 450    }
 451    return buf;
 452  }
 453  
 454  //! @brief error_chars
 455  
 456  static char *error_chars (char *buf, int n)
 457  {
 458    int k = (n != 0 ? ABS (n) : 1);
 459    buf[k] = '\0';
 460    while (--k >= 0) {
 461      buf[k] = ERROR_CHAR;
 462    }
 463    return buf;
 464  }
 465  
 466  //! @brief strputc_quad_real
 467  
 468  void strputc_quad_real (char c, char *buffer)
 469  {
 470  // Assumes that buffer is initially filled with \0.
 471    char *ptr;
 472    for (ptr = buffer; *ptr != '\0'; ptr++);
 473    *ptr = c;
 474  }
 475  
 476  //! @brief sprintfmt_quad_real
 477  
 478  void sprintfmt_quad_real (char *buffer, const char *fmt, ...)
 479  {
 480    BUFFER ibuff;
 481    BUFCLR (ibuff);
 482    va_list ap;
 483    va_start (ap, fmt);
 484    vsprintf (ibuff, fmt, ap);
 485    va_end (ap);
 486    strcat (buffer, ibuff);
 487  }
 488  
 489  static int special_value (char *s, QUAD_T u, int sign)
 490  {
 491    if ((isPinf_quad_real (&u))) {
 492      if (sign != 0) {
 493        *s++ = '+';
 494      }
 495      strcpy (s, "Inf");
 496      return 1;
 497    } else if ((isMinf_quad_real (&u))) {
 498      strcpy (s, "-Inf");
 499      return 1;
 500    } else if ((isNaN_quad_real (&u))) {
 501      if (sign != 0) {
 502        *s++ = '\?';
 503      }
 504      strcpy (s, "NaN");
 505      return 1;
 506    } else {
 507      return 0;
 508    }
 509  }
 510  
 511  //! @brief subfixed_quad_real
 512  
 513  char *subfixed_quad_real (char *buffer, QUAD_T u, int sign, int digs)
 514  {
 515    BUFCLR (buffer);
 516    if ((special_value (buffer, u, sign))) {
 517      return buffer;
 518    }
 519  // Added for VIF to be compatible with fortran F format.
 520    QUAD_T t = abs_quad_real (u);
 521    while (ge_quad_real (t, QUAD_REAL_TEN)) {
 522      t = div_quad_real (t, QUAD_REAL_TEN);
 523      digs++;
 524    }
 525  // -- end of addition.
 526    digs = MIN (ABS (digs), FLT256_DIG);
 527  // Put sign and take abs value.
 528    unt_2 *pa = (unt_2 *) &QV (u);
 529    if ((*pa & QUAD_REAL_M_SIGN)) {
 530      *pa ^= QUAD_REAL_M_SIGN;
 531      strputc_quad_real ('-', buffer);
 532    } else if (sign) {
 533      strputc_quad_real ('+', buffer);
 534    }
 535  // Zero as special case.
 536    int k;
 537    if ((is0_quad_real (&u))) {
 538      sprintfmt_quad_real (buffer, "0.");
 539      for (k = 0; k < digs; ++k) {
 540        strputc_quad_real ('0', buffer);
 541      }
 542      return buffer;
 543    }
 544  // Reduce argument.
 545    int mag = ((*pa & QUAD_REAL_M_EXP) - QUAD_REAL_BIAS);
 546    mag = (int) ((REAL_T) (mag + 1) * M_LOG10_2);
 547    if ((mag != 0)) {
 548      u = mul_quad_real (u, pwr_quad_real (QUAD_REAL_TEN, -mag));
 549    }
 550    while ((*pa & QUAD_REAL_M_EXP) < QUAD_REAL_BIAS) {
 551      --mag;
 552      u = mul_quad_real (u, QUAD_REAL_TEN);
 553    }
 554    if (mag < 0) {
 555      digs = MAX (0, digs + mag);
 556    }
 557  // We store digits as pseudo-chars.
 558    BUFFER q;
 559    BUFCLR (q);
 560    char *p = q;
 561    BUFCLR (q);
 562  //
 563    int dig;
 564    for (*p = 0, k = 0; k <= digs; ++k) {
 565      u = sfmod_quad_real (u, &dig);
 566      *(++p) = (char) dig;
 567      if (*pa == 0) {
 568        break;
 569      }
 570      u = mul_quad_real (QUAD_REAL_TEN, u);
 571    }
 572  // Round fraction
 573    if (*pa != 0) {
 574      u = sfmod_quad_real (u, &dig);
 575      if (dig >= 5) {
 576        ++(*p);
 577      }
 578      while (*p == 10) {
 579        *p = 0;
 580        ++(*--p);
 581      }
 582    }
 583    p = q;
 584    if (*p == 0) {
 585      ++p;
 586    } else {
 587      ++mag;
 588    }
 589  // Now sprintf 
 590    if (mag > QUAD_REAL_MAX_10EX) {
 591      sprintfmt_quad_real (buffer, "Inf");
 592      return buffer;
 593    }
 594  //
 595    if (mag >= 0) {
 596      for (k = 0; k <= mag; k++) {
 597        if (k <= digs) {
 598          strputc_quad_real ('0' + p[k], buffer);
 599        } else {
 600          strputc_quad_real ('0', buffer);
 601        }
 602      }
 603      if (k <= digs) {
 604        strputc_quad_real ('.', buffer);
 605        for (; k <= digs; k++) {
 606          strputc_quad_real ('0' + p[k], buffer);
 607        }
 608      }
 609    } else {
 610      sprintfmt_quad_real (buffer, "0.");
 611      for (k = 1; k < ABS (mag) && digs >= 0; k++) {
 612        strputc_quad_real ('0', buffer);
 613        digs--;
 614      }
 615      for (k = 0; k <= digs; ++k) {
 616        strputc_quad_real ('0' + *p++, buffer);
 617      }
 618    }
 619    return buffer;
 620  }
 621  
 622  //! @brief fixed_quad_real
 623  
 624  char *fixed_quad_real (char *buf, QUAD_T x, int width, int digs, int precision)
 625  {
 626    width = ABS (width);
 627    digs = MIN (abs (digs), precision);
 628    subfixed_quad_real (buf, x, 0, digs);
 629    if (width > 0 && strlen (buf) > width) {
 630      return error_chars (buf, width);
 631    } else {
 632      return leading_spaces (buf, width);
 633    }
 634  }
 635  
 636  //! @brief float_quad_real
 637  
 638  char *float_quad_real (char *buf, QUAD_T z, int width, int digs, int expos, int mult, int precision, char sym)
 639  {
 640    buf[0] = '\0';
 641    width = ABS (width);
 642    digs = MIN (abs (digs), precision);
 643    expos = ABS (expos);
 644    if (expos > 5) {
 645      return error_chars (buf, width);
 646    }
 647  // Scientific notation mult = 1, Engineering notation mult = 3
 648    mult = MAX (1, mult);
 649  // Default _scale_ is 1.
 650    int q = 1;
 651    char *max = "1";
 652    QUAD_T x = abs_quad_real (z), lwb, upb;
 653  //
 654    if (_scale_ < 0 || _scale_ > 3) {
 655      _scale_ = 1;
 656    }
 657    if (mult == 1) {
 658      if (_scale_ == 0) {
 659        lwb = QUAD_REAL_TENTH;
 660        upb = QUAD_REAL_ONE;
 661        q = 1;
 662        max = "0.1";
 663      } else if (_scale_ == 1) {
 664        lwb = QUAD_REAL_ONE;
 665        upb = QUAD_REAL_TEN;
 666        q = 0;
 667        max = "1";
 668      } else if (_scale_ == 2) {
 669        lwb = QUAD_REAL_TEN;
 670        upb = QUAD_REAL_HUNDRED;
 671        q = -1;
 672        max = "10";
 673      } else if (_scale_ == 3) {
 674        lwb = QUAD_REAL_HUNDRED;
 675        upb = QUAD_REAL_THOUSAND;
 676        max = "100";
 677        q = -2;
 678      }
 679    }
 680  // Standardize.
 681    int p = 0;
 682    if (not0_quad_real (&x)) {
 683      p = (int) round (quad_real_to_real (log10_quad_real (abs_quad_real(x)))) + q;
 684      x = div_quad_real (x, ten_up_quad_real (p));
 685      if (le_quad_real (x, lwb)) {
 686        x = mul_quad_real (x, QUAD_REAL_TEN);
 687        p--;
 688      } 
 689      if (ge_quad_real (x, upb)) {
 690        x = div_quad_real (x, QUAD_REAL_TEN);
 691        p++;
 692      } 
 693      while (p % mult != 0) {
 694        x = mul_quad_real (x, QUAD_REAL_TEN);
 695        p--;
 696      }
 697    }
 698  // Form number.
 699    BUFFER mant;
 700    subfixed_quad_real (mant, x, 0, digs);
 701  // Correction of rounding issue by which |mant| equals UPB.
 702    if (strchr (mant, '*') == NULL && ge_quad_real (abs_quad_real (string_to_quad_real (mant, NULL)), upb)) {
 703      srecordf (mant, "%s", max);
 704      if (digs > 0) {
 705        plusab (mant, '.');
 706        for (int k = 0; k < digs; k++) {
 707          plusab (mant, '0');
 708        }
 709      }
 710      p++;
 711    }
 712  //
 713    BUFFER fmt;
 714    if (sgn_quad_real (&z) >= 0) {
 715      srecordf (fmt, " %%s%c%%+0%dd", sym, expos);
 716    } else {
 717      srecordf (fmt, "-%%s%c%%+0%dd", sym, expos);
 718    }
 719    srecordf (buf, fmt, mant, p);
 720    if (width > 0 && (strchr (buf, '*') != NULL || strlen (buf) > width)) {
 721      if (digs > 0) {
 722        return float_quad_real (buf, z, width, digs - 1, expos, mult, precision, sym);
 723      } else {
 724        return error_chars (buf, width);
 725      }
 726    } else {
 727      return leading_spaces (buf, width);
 728    }
 729  }
 730  
 731  #endif