164ab3302SCarolineConcatto //===-- lib/Decimal/decimal-to-binary.cpp ---------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #include "big-radix-floating-point.h"
1064ab3302SCarolineConcatto #include "flang/Common/bit-population-count.h"
1164ab3302SCarolineConcatto #include "flang/Common/leading-zero-bit-count.h"
1264ab3302SCarolineConcatto #include "flang/Decimal/binary-floating-point.h"
1364ab3302SCarolineConcatto #include "flang/Decimal/decimal.h"
1464ab3302SCarolineConcatto #include <cinttypes>
1564ab3302SCarolineConcatto #include <cstring>
1664ab3302SCarolineConcatto #include <ctype.h>
1764ab3302SCarolineConcatto 
1864ab3302SCarolineConcatto namespace Fortran::decimal {
1964ab3302SCarolineConcatto 
2064ab3302SCarolineConcatto template <int PREC, int LOG10RADIX>
2164ab3302SCarolineConcatto bool BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ParseNumber(
2264ab3302SCarolineConcatto     const char *&p, bool &inexact) {
2364ab3302SCarolineConcatto   SetToZero();
2464ab3302SCarolineConcatto   while (*p == ' ') {
2564ab3302SCarolineConcatto     ++p;
2664ab3302SCarolineConcatto   }
2764ab3302SCarolineConcatto   const char *q{p};
2864ab3302SCarolineConcatto   isNegative_ = *q == '-';
2964ab3302SCarolineConcatto   if (*q == '-' || *q == '+') {
3064ab3302SCarolineConcatto     ++q;
3164ab3302SCarolineConcatto   }
3264ab3302SCarolineConcatto   const char *start{q};
3364ab3302SCarolineConcatto   while (*q == '0') {
3464ab3302SCarolineConcatto     ++q;
3564ab3302SCarolineConcatto   }
3664ab3302SCarolineConcatto   const char *first{q};
3764ab3302SCarolineConcatto   for (; *q >= '0' && *q <= '9'; ++q) {
3864ab3302SCarolineConcatto   }
3964ab3302SCarolineConcatto   const char *point{nullptr};
4064ab3302SCarolineConcatto   if (*q == '.') {
4164ab3302SCarolineConcatto     point = q;
4264ab3302SCarolineConcatto     for (++q; *q >= '0' && *q <= '9'; ++q) {
4364ab3302SCarolineConcatto     }
4464ab3302SCarolineConcatto   }
4564ab3302SCarolineConcatto   if (q == start || (q == start + 1 && *start == '.')) {
4664ab3302SCarolineConcatto     return false; // require at least one digit
4764ab3302SCarolineConcatto   }
4864ab3302SCarolineConcatto   // There's a valid number here; set the reference argument to point to
4964ab3302SCarolineConcatto   // the first character afterward.
5064ab3302SCarolineConcatto   p = q;
5164ab3302SCarolineConcatto   // Strip off trailing zeroes
5264ab3302SCarolineConcatto   if (point) {
5364ab3302SCarolineConcatto     while (q[-1] == '0') {
5464ab3302SCarolineConcatto       --q;
5564ab3302SCarolineConcatto     }
5664ab3302SCarolineConcatto     if (q[-1] == '.') {
5764ab3302SCarolineConcatto       point = nullptr;
5864ab3302SCarolineConcatto       --q;
5964ab3302SCarolineConcatto     }
6064ab3302SCarolineConcatto   }
6164ab3302SCarolineConcatto   if (!point) {
6264ab3302SCarolineConcatto     while (q > first && q[-1] == '0') {
6364ab3302SCarolineConcatto       --q;
6464ab3302SCarolineConcatto       ++exponent_;
6564ab3302SCarolineConcatto     }
6664ab3302SCarolineConcatto   }
6764ab3302SCarolineConcatto   // Trim any excess digits
6864ab3302SCarolineConcatto   const char *limit{first + maxDigits * log10Radix + (point != nullptr)};
6964ab3302SCarolineConcatto   if (q > limit) {
7064ab3302SCarolineConcatto     inexact = true;
7164ab3302SCarolineConcatto     if (point >= limit) {
7264ab3302SCarolineConcatto       q = point;
7364ab3302SCarolineConcatto       point = nullptr;
7464ab3302SCarolineConcatto     }
7564ab3302SCarolineConcatto     if (!point) {
7664ab3302SCarolineConcatto       exponent_ += q - limit;
7764ab3302SCarolineConcatto     }
7864ab3302SCarolineConcatto     q = limit;
7964ab3302SCarolineConcatto   }
8064ab3302SCarolineConcatto   if (point) {
8164ab3302SCarolineConcatto     exponent_ -= static_cast<int>(q - point - 1);
8264ab3302SCarolineConcatto   }
8364ab3302SCarolineConcatto   if (q == first) {
8464ab3302SCarolineConcatto     exponent_ = 0; // all zeros
8564ab3302SCarolineConcatto   }
8664ab3302SCarolineConcatto   // Rack the decimal digits up into big Digits.
8764ab3302SCarolineConcatto   for (auto times{radix}; q-- > first;) {
8864ab3302SCarolineConcatto     if (*q != '.') {
8964ab3302SCarolineConcatto       if (times == radix) {
9064ab3302SCarolineConcatto         digit_[digits_++] = *q - '0';
9164ab3302SCarolineConcatto         times = 10;
9264ab3302SCarolineConcatto       } else {
9364ab3302SCarolineConcatto         digit_[digits_ - 1] += times * (*q - '0');
9464ab3302SCarolineConcatto         times *= 10;
9564ab3302SCarolineConcatto       }
9664ab3302SCarolineConcatto     }
9764ab3302SCarolineConcatto   }
9864ab3302SCarolineConcatto   // Look for an optional exponent field.
9964ab3302SCarolineConcatto   q = p;
10064ab3302SCarolineConcatto   switch (*q) {
10164ab3302SCarolineConcatto   case 'e':
10264ab3302SCarolineConcatto   case 'E':
10364ab3302SCarolineConcatto   case 'd':
10464ab3302SCarolineConcatto   case 'D':
10564ab3302SCarolineConcatto   case 'q':
10664ab3302SCarolineConcatto   case 'Q': {
10764ab3302SCarolineConcatto     bool negExpo{*++q == '-'};
10864ab3302SCarolineConcatto     if (*q == '-' || *q == '+') {
10964ab3302SCarolineConcatto       ++q;
11064ab3302SCarolineConcatto     }
11164ab3302SCarolineConcatto     if (*q >= '0' && *q <= '9') {
11264ab3302SCarolineConcatto       int expo{0};
11364ab3302SCarolineConcatto       while (*q == '0') {
11464ab3302SCarolineConcatto         ++q;
11564ab3302SCarolineConcatto       }
11664ab3302SCarolineConcatto       const char *expDig{q};
11764ab3302SCarolineConcatto       while (*q >= '0' && *q <= '9') {
11864ab3302SCarolineConcatto         expo = 10 * expo + *q++ - '0';
11964ab3302SCarolineConcatto       }
12064ab3302SCarolineConcatto       if (q >= expDig + 8) {
12164ab3302SCarolineConcatto         // There's a ridiculous number of nonzero exponent digits.
12264ab3302SCarolineConcatto         // The decimal->binary conversion routine will cope with
12364ab3302SCarolineConcatto         // returning 0 or Inf, but we must ensure that "expo" didn't
12464ab3302SCarolineConcatto         // overflow back around to something legal.
12564ab3302SCarolineConcatto         expo = 10 * Real::decimalRange;
12664ab3302SCarolineConcatto         exponent_ = 0;
12764ab3302SCarolineConcatto       }
12864ab3302SCarolineConcatto       p = q; // exponent was valid
12964ab3302SCarolineConcatto       if (negExpo) {
13064ab3302SCarolineConcatto         exponent_ -= expo;
13164ab3302SCarolineConcatto       } else {
13264ab3302SCarolineConcatto         exponent_ += expo;
13364ab3302SCarolineConcatto       }
13464ab3302SCarolineConcatto     }
13564ab3302SCarolineConcatto   } break;
1361f879005STim Keith   default:
1371f879005STim Keith     break;
13864ab3302SCarolineConcatto   }
13964ab3302SCarolineConcatto   return true;
14064ab3302SCarolineConcatto }
14164ab3302SCarolineConcatto 
142*6fec2c44Speter klausler template <int PREC, int LOG10RADIX>
143*6fec2c44Speter klausler void BigRadixFloatingPointNumber<PREC,
144*6fec2c44Speter klausler     LOG10RADIX>::LoseLeastSignificantDigit() {
145*6fec2c44Speter klausler   Digit LSD{digit_[0]};
146*6fec2c44Speter klausler   for (int j{0}; j < digits_ - 1; ++j) {
147*6fec2c44Speter klausler     digit_[j] = digit_[j + 1];
148*6fec2c44Speter klausler   }
149*6fec2c44Speter klausler   digit_[digits_ - 1] = 0;
150*6fec2c44Speter klausler   bool incr{false};
151*6fec2c44Speter klausler   switch (rounding_) {
152*6fec2c44Speter klausler   case RoundNearest:
153*6fec2c44Speter klausler   case RoundDefault:
154*6fec2c44Speter klausler     incr = LSD > radix / 2 || (LSD == radix / 2 && digit_[0] % 2 != 0);
155*6fec2c44Speter klausler     break;
156*6fec2c44Speter klausler   case RoundUp:
157*6fec2c44Speter klausler     incr = LSD > 0 && !isNegative_;
158*6fec2c44Speter klausler     break;
159*6fec2c44Speter klausler   case RoundDown:
160*6fec2c44Speter klausler     incr = LSD > 0 && isNegative_;
161*6fec2c44Speter klausler     break;
162*6fec2c44Speter klausler   case RoundToZero:
163*6fec2c44Speter klausler     break;
164*6fec2c44Speter klausler   case RoundCompatible:
165*6fec2c44Speter klausler     incr = LSD >= radix / 2;
166*6fec2c44Speter klausler     break;
167*6fec2c44Speter klausler   }
168*6fec2c44Speter klausler   for (int j{0}; (digit_[j] += incr) == radix; ++j) {
169*6fec2c44Speter klausler     digit_[j] = 0;
170*6fec2c44Speter klausler   }
171*6fec2c44Speter klausler }
172*6fec2c44Speter klausler 
17364ab3302SCarolineConcatto // This local utility class represents an unrounded nonnegative
17464ab3302SCarolineConcatto // binary floating-point value with an unbiased (i.e., signed)
17564ab3302SCarolineConcatto // binary exponent, an integer value (not a fraction) with an implied
17664ab3302SCarolineConcatto // binary point to its *right*, and some guard bits for rounding.
17764ab3302SCarolineConcatto template <int PREC> class IntermediateFloat {
17864ab3302SCarolineConcatto public:
17964ab3302SCarolineConcatto   static constexpr int precision{PREC};
18064ab3302SCarolineConcatto   using IntType = common::HostUnsignedIntType<precision>;
18164ab3302SCarolineConcatto   static constexpr IntType topBit{IntType{1} << (precision - 1)};
18264ab3302SCarolineConcatto   static constexpr IntType mask{topBit + (topBit - 1)};
18364ab3302SCarolineConcatto 
18464ab3302SCarolineConcatto   IntermediateFloat() {}
18564ab3302SCarolineConcatto   IntermediateFloat(const IntermediateFloat &) = default;
18664ab3302SCarolineConcatto 
18764ab3302SCarolineConcatto   // Assumes that exponent_ is valid on entry, and may increment it.
18864ab3302SCarolineConcatto   // Returns the number of guard_ bits that have been determined.
18964ab3302SCarolineConcatto   template <typename UINT> bool SetTo(UINT n) {
19064ab3302SCarolineConcatto     static constexpr int nBits{CHAR_BIT * sizeof n};
19164ab3302SCarolineConcatto     if constexpr (precision >= nBits) {
19264ab3302SCarolineConcatto       value_ = n;
19364ab3302SCarolineConcatto       guard_ = 0;
19464ab3302SCarolineConcatto       return 0;
19564ab3302SCarolineConcatto     } else {
19664ab3302SCarolineConcatto       int shift{common::BitsNeededFor(n) - precision};
19764ab3302SCarolineConcatto       if (shift <= 0) {
19864ab3302SCarolineConcatto         value_ = n;
19964ab3302SCarolineConcatto         guard_ = 0;
20064ab3302SCarolineConcatto         return 0;
20164ab3302SCarolineConcatto       } else {
20264ab3302SCarolineConcatto         value_ = n >> shift;
20364ab3302SCarolineConcatto         exponent_ += shift;
20464ab3302SCarolineConcatto         n <<= nBits - shift;
20564ab3302SCarolineConcatto         guard_ = (n >> (nBits - guardBits)) | ((n << guardBits) != 0);
20664ab3302SCarolineConcatto         return shift;
20764ab3302SCarolineConcatto       }
20864ab3302SCarolineConcatto     }
20964ab3302SCarolineConcatto   }
21064ab3302SCarolineConcatto 
21164ab3302SCarolineConcatto   void ShiftIn(int bit = 0) { value_ = value_ + value_ + bit; }
21264ab3302SCarolineConcatto   bool IsFull() const { return value_ >= topBit; }
21364ab3302SCarolineConcatto   void AdjustExponent(int by) { exponent_ += by; }
21464ab3302SCarolineConcatto   void SetGuard(int g) {
21564ab3302SCarolineConcatto     guard_ |= (static_cast<GuardType>(g & 6) << (guardBits - 3)) | (g & 1);
21664ab3302SCarolineConcatto   }
21764ab3302SCarolineConcatto 
21864ab3302SCarolineConcatto   ConversionToBinaryResult<PREC> ToBinary(
21964ab3302SCarolineConcatto       bool isNegative, FortranRounding) const;
22064ab3302SCarolineConcatto 
22164ab3302SCarolineConcatto private:
22264ab3302SCarolineConcatto   static constexpr int guardBits{3}; // guard, round, sticky
22364ab3302SCarolineConcatto   using GuardType = int;
22464ab3302SCarolineConcatto   static constexpr GuardType oneHalf{GuardType{1} << (guardBits - 1)};
22564ab3302SCarolineConcatto 
22664ab3302SCarolineConcatto   IntType value_{0};
22764ab3302SCarolineConcatto   GuardType guard_{0};
22864ab3302SCarolineConcatto   int exponent_{0};
22964ab3302SCarolineConcatto };
23064ab3302SCarolineConcatto 
23164ab3302SCarolineConcatto template <int PREC>
23264ab3302SCarolineConcatto ConversionToBinaryResult<PREC> IntermediateFloat<PREC>::ToBinary(
23364ab3302SCarolineConcatto     bool isNegative, FortranRounding rounding) const {
23464ab3302SCarolineConcatto   using Binary = BinaryFloatingPointNumber<PREC>;
23564ab3302SCarolineConcatto   // Create a fraction with a binary point to the left of the integer
23664ab3302SCarolineConcatto   // value_, and bias the exponent.
23764ab3302SCarolineConcatto   IntType fraction{value_};
23864ab3302SCarolineConcatto   GuardType guard{guard_};
23964ab3302SCarolineConcatto   int expo{exponent_ + Binary::exponentBias + (precision - 1)};
24064ab3302SCarolineConcatto   while (expo < 1 && (fraction > 0 || guard > oneHalf)) {
24164ab3302SCarolineConcatto     guard = (guard & 1) | (guard >> 1) |
24264ab3302SCarolineConcatto         ((static_cast<GuardType>(fraction) & 1) << (guardBits - 1));
24364ab3302SCarolineConcatto     fraction >>= 1;
24464ab3302SCarolineConcatto     ++expo;
24564ab3302SCarolineConcatto   }
24664ab3302SCarolineConcatto   int flags{Exact};
24764ab3302SCarolineConcatto   if (guard != 0) {
24864ab3302SCarolineConcatto     flags |= Inexact;
24964ab3302SCarolineConcatto   }
25064ab3302SCarolineConcatto   if (fraction == 0 && guard <= oneHalf) {
25164ab3302SCarolineConcatto     return {Binary{}, static_cast<enum ConversionResultFlags>(flags)};
25264ab3302SCarolineConcatto   }
25364ab3302SCarolineConcatto   // The value is nonzero; normalize it.
25464ab3302SCarolineConcatto   while (fraction < topBit && expo > 1) {
25564ab3302SCarolineConcatto     --expo;
25664ab3302SCarolineConcatto     fraction = fraction * 2 + (guard >> (guardBits - 2));
25764ab3302SCarolineConcatto     guard = (((guard >> (guardBits - 2)) & 1) << (guardBits - 1)) | (guard & 1);
25864ab3302SCarolineConcatto   }
25964ab3302SCarolineConcatto   // Apply rounding
26064ab3302SCarolineConcatto   bool incr{false};
26164ab3302SCarolineConcatto   switch (rounding) {
26264ab3302SCarolineConcatto   case RoundNearest:
26364ab3302SCarolineConcatto   case RoundDefault:
26464ab3302SCarolineConcatto     incr = guard > oneHalf || (guard == oneHalf && (fraction & 1));
26564ab3302SCarolineConcatto     break;
2661f879005STim Keith   case RoundUp:
2671f879005STim Keith     incr = guard != 0 && !isNegative;
2681f879005STim Keith     break;
2691f879005STim Keith   case RoundDown:
2701f879005STim Keith     incr = guard != 0 && isNegative;
2711f879005STim Keith     break;
2721f879005STim Keith   case RoundToZero:
2731f879005STim Keith     break;
2741f879005STim Keith   case RoundCompatible:
2751f879005STim Keith     incr = guard >= oneHalf;
2761f879005STim Keith     break;
27764ab3302SCarolineConcatto   }
27864ab3302SCarolineConcatto   if (incr) {
27964ab3302SCarolineConcatto     if (fraction == mask) {
28064ab3302SCarolineConcatto       // rounding causes a carry
28164ab3302SCarolineConcatto       ++expo;
28264ab3302SCarolineConcatto       fraction = topBit;
28364ab3302SCarolineConcatto     } else {
28464ab3302SCarolineConcatto       ++fraction;
28564ab3302SCarolineConcatto     }
28664ab3302SCarolineConcatto   }
28764ab3302SCarolineConcatto   if (expo == 1 && fraction < topBit) {
28864ab3302SCarolineConcatto     expo = 0; // subnormal
28964ab3302SCarolineConcatto   }
29064ab3302SCarolineConcatto   if (expo >= Binary::maxExponent) {
29164ab3302SCarolineConcatto     expo = Binary::maxExponent; // Inf
29264ab3302SCarolineConcatto     flags |= Overflow;
29364ab3302SCarolineConcatto     fraction = 0;
29464ab3302SCarolineConcatto   }
29564ab3302SCarolineConcatto   using Raw = typename Binary::RawType;
29664ab3302SCarolineConcatto   Raw raw = static_cast<Raw>(isNegative) << (Binary::bits - 1);
29764ab3302SCarolineConcatto   raw |= static_cast<Raw>(expo) << Binary::significandBits;
29864ab3302SCarolineConcatto   if constexpr (Binary::isImplicitMSB) {
29964ab3302SCarolineConcatto     fraction &= ~topBit;
30064ab3302SCarolineConcatto   }
30164ab3302SCarolineConcatto   raw |= fraction;
30264ab3302SCarolineConcatto   return {Binary(raw), static_cast<enum ConversionResultFlags>(flags)};
30364ab3302SCarolineConcatto }
30464ab3302SCarolineConcatto 
30564ab3302SCarolineConcatto template <int PREC, int LOG10RADIX>
30664ab3302SCarolineConcatto ConversionToBinaryResult<PREC>
30764ab3302SCarolineConcatto BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary() {
30864ab3302SCarolineConcatto   // On entry, *this holds a multi-precision integer value in a radix of a
30964ab3302SCarolineConcatto   // large power of ten.  Its radix point is defined to be to the right of its
31064ab3302SCarolineConcatto   // digits, and "exponent_" is the power of ten by which it is to be scaled.
31164ab3302SCarolineConcatto   Normalize();
31264ab3302SCarolineConcatto   if (digits_ == 0) { // zero value
31364ab3302SCarolineConcatto     return {Real{SignBit()}};
31464ab3302SCarolineConcatto   }
31564ab3302SCarolineConcatto   // The value is not zero:  x = D. * 10.**E
31664ab3302SCarolineConcatto   // Shift our perspective on the radix (& decimal) point so that
31764ab3302SCarolineConcatto   // it sits to the *left* of the digits: i.e., x = .D * 10.**E
31864ab3302SCarolineConcatto   exponent_ += digits_ * log10Radix;
31964ab3302SCarolineConcatto   // Sanity checks for ridiculous exponents
32064ab3302SCarolineConcatto   static constexpr int crazy{2 * Real::decimalRange + log10Radix};
32164ab3302SCarolineConcatto   if (exponent_ < -crazy) { // underflow to +/-0.
32264ab3302SCarolineConcatto     return {Real{SignBit()}, Inexact};
32364ab3302SCarolineConcatto   } else if (exponent_ > crazy) { // overflow to +/-Inf.
32464ab3302SCarolineConcatto     return {Real{Infinity()}, Overflow};
32564ab3302SCarolineConcatto   }
32664ab3302SCarolineConcatto   // Apply any negative decimal exponent by multiplication
32764ab3302SCarolineConcatto   // by a power of two, adjusting the binary exponent to compensate.
32864ab3302SCarolineConcatto   IntermediateFloat<PREC> f;
32964ab3302SCarolineConcatto   while (exponent_ < log10Radix) {
33064ab3302SCarolineConcatto     // x = 0.D * 10.**E * 2.**(f.ex) -> 512 * 0.D * 10.**E * 2.**(f.ex-9)
33164ab3302SCarolineConcatto     f.AdjustExponent(-9);
33264ab3302SCarolineConcatto     digitLimit_ = digits_;
33364ab3302SCarolineConcatto     if (int carry{MultiplyWithoutNormalization<512>()}) {
33464ab3302SCarolineConcatto       // x = c.D * 10.**E * 2.**(f.ex) -> .cD * 10.**(E+16) * 2.**(f.ex)
33564ab3302SCarolineConcatto       PushCarry(carry);
33664ab3302SCarolineConcatto       exponent_ += log10Radix;
33764ab3302SCarolineConcatto     }
33864ab3302SCarolineConcatto   }
33964ab3302SCarolineConcatto   // Apply any positive decimal exponent greater than
34064ab3302SCarolineConcatto   // is needed to treat the topmost digit as an integer
34164ab3302SCarolineConcatto   // part by multiplying by 10 or 10000 repeatedly.
34264ab3302SCarolineConcatto   while (exponent_ > log10Radix) {
34364ab3302SCarolineConcatto     digitLimit_ = digits_;
34464ab3302SCarolineConcatto     int carry;
34564ab3302SCarolineConcatto     if (exponent_ >= log10Radix + 4) {
34664ab3302SCarolineConcatto       // x = 0.D * 10.**E * 2.**(f.ex) -> 625 * .D * 10.**(E-4) * 2.**(f.ex+4)
34764ab3302SCarolineConcatto       exponent_ -= 4;
34864ab3302SCarolineConcatto       carry = MultiplyWithoutNormalization<(5 * 5 * 5 * 5)>();
34964ab3302SCarolineConcatto       f.AdjustExponent(4);
35064ab3302SCarolineConcatto     } else {
35164ab3302SCarolineConcatto       // x = 0.D * 10.**E * 2.**(f.ex) -> 5 * .D * 10.**(E-1) * 2.**(f.ex+1)
35264ab3302SCarolineConcatto       --exponent_;
35364ab3302SCarolineConcatto       carry = MultiplyWithoutNormalization<5>();
35464ab3302SCarolineConcatto       f.AdjustExponent(1);
35564ab3302SCarolineConcatto     }
35664ab3302SCarolineConcatto     if (carry != 0) {
35764ab3302SCarolineConcatto       // x = c.D * 10.**E * 2.**(f.ex) -> .cD * 10.**(E+16) * 2.**(f.ex)
35864ab3302SCarolineConcatto       PushCarry(carry);
35964ab3302SCarolineConcatto       exponent_ += log10Radix;
36064ab3302SCarolineConcatto     }
36164ab3302SCarolineConcatto   }
36264ab3302SCarolineConcatto   // So exponent_ is now log10Radix, meaning that the
36364ab3302SCarolineConcatto   // MSD can be taken as an integer part and transferred
36464ab3302SCarolineConcatto   // to the binary result.
36564ab3302SCarolineConcatto   // x = .jD * 10.**16 * 2.**(f.ex) -> .D * j * 2.**(f.ex)
36664ab3302SCarolineConcatto   int guardShift{f.SetTo(digit_[--digits_])};
36764ab3302SCarolineConcatto   // Transfer additional bits until the result is normal.
36864ab3302SCarolineConcatto   digitLimit_ = digits_;
36964ab3302SCarolineConcatto   while (!f.IsFull()) {
37064ab3302SCarolineConcatto     // x = ((b.D)/2) * j * 2.**(f.ex) -> .D * (2j + b) * 2.**(f.ex-1)
37164ab3302SCarolineConcatto     f.AdjustExponent(-1);
37264ab3302SCarolineConcatto     std::uint32_t carry = MultiplyWithoutNormalization<2>();
37364ab3302SCarolineConcatto     f.ShiftIn(carry);
37464ab3302SCarolineConcatto   }
37564ab3302SCarolineConcatto   // Get the next few bits for rounding.  Allow for some guard bits
37664ab3302SCarolineConcatto   // that may have already been set in f.SetTo() above.
37764ab3302SCarolineConcatto   int guard{0};
37864ab3302SCarolineConcatto   if (guardShift == 0) {
37964ab3302SCarolineConcatto     guard = MultiplyWithoutNormalization<4>();
38064ab3302SCarolineConcatto   } else if (guardShift == 1) {
38164ab3302SCarolineConcatto     guard = MultiplyWithoutNormalization<2>();
38264ab3302SCarolineConcatto   }
38364ab3302SCarolineConcatto   guard = guard + guard + !IsZero();
38464ab3302SCarolineConcatto   f.SetGuard(guard);
38564ab3302SCarolineConcatto   return f.ToBinary(isNegative_, rounding_);
38664ab3302SCarolineConcatto }
38764ab3302SCarolineConcatto 
38864ab3302SCarolineConcatto template <int PREC, int LOG10RADIX>
38964ab3302SCarolineConcatto ConversionToBinaryResult<PREC>
39064ab3302SCarolineConcatto BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary(const char *&p) {
39164ab3302SCarolineConcatto   bool inexact{false};
39264ab3302SCarolineConcatto   if (ParseNumber(p, inexact)) {
39364ab3302SCarolineConcatto     auto result{ConvertToBinary()};
39464ab3302SCarolineConcatto     if (inexact) {
39564ab3302SCarolineConcatto       result.flags =
39664ab3302SCarolineConcatto           static_cast<enum ConversionResultFlags>(result.flags | Inexact);
39764ab3302SCarolineConcatto     }
39864ab3302SCarolineConcatto     return result;
39964ab3302SCarolineConcatto   } else {
40064ab3302SCarolineConcatto     // Could not parse a decimal floating-point number.  p has been
40164ab3302SCarolineConcatto     // advanced over any leading spaces.
40264ab3302SCarolineConcatto     if (toupper(p[0]) == 'N' && toupper(p[1]) == 'A' && toupper(p[2]) == 'N') {
40364ab3302SCarolineConcatto       // NaN
40464ab3302SCarolineConcatto       p += 3;
40564ab3302SCarolineConcatto       return {Real{NaN()}};
40664ab3302SCarolineConcatto     } else {
40764ab3302SCarolineConcatto       // Try to parse Inf, maybe with a sign
40864ab3302SCarolineConcatto       const char *q{p};
40964ab3302SCarolineConcatto       isNegative_ = *q == '-';
41064ab3302SCarolineConcatto       if (*q == '-' || *q == '+') {
41164ab3302SCarolineConcatto         ++q;
41264ab3302SCarolineConcatto       }
41364ab3302SCarolineConcatto       if (toupper(q[0]) == 'I' && toupper(q[1]) == 'N' &&
41464ab3302SCarolineConcatto           toupper(q[2]) == 'F') {
41564ab3302SCarolineConcatto         p = q + 3;
41664ab3302SCarolineConcatto         return {Real{Infinity()}};
41764ab3302SCarolineConcatto       } else {
41864ab3302SCarolineConcatto         // Invalid input
41964ab3302SCarolineConcatto         return {Real{NaN()}, Invalid};
42064ab3302SCarolineConcatto       }
42164ab3302SCarolineConcatto     }
42264ab3302SCarolineConcatto   }
42364ab3302SCarolineConcatto }
42464ab3302SCarolineConcatto 
42564ab3302SCarolineConcatto template <int PREC>
42664ab3302SCarolineConcatto ConversionToBinaryResult<PREC> ConvertToBinary(
42764ab3302SCarolineConcatto     const char *&p, enum FortranRounding rounding) {
42864ab3302SCarolineConcatto   return BigRadixFloatingPointNumber<PREC>{rounding}.ConvertToBinary(p);
42964ab3302SCarolineConcatto }
43064ab3302SCarolineConcatto 
43164ab3302SCarolineConcatto template ConversionToBinaryResult<8> ConvertToBinary<8>(
43264ab3302SCarolineConcatto     const char *&, enum FortranRounding);
43364ab3302SCarolineConcatto template ConversionToBinaryResult<11> ConvertToBinary<11>(
43464ab3302SCarolineConcatto     const char *&, enum FortranRounding);
43564ab3302SCarolineConcatto template ConversionToBinaryResult<24> ConvertToBinary<24>(
43664ab3302SCarolineConcatto     const char *&, enum FortranRounding);
43764ab3302SCarolineConcatto template ConversionToBinaryResult<53> ConvertToBinary<53>(
43864ab3302SCarolineConcatto     const char *&, enum FortranRounding);
43964ab3302SCarolineConcatto template ConversionToBinaryResult<64> ConvertToBinary<64>(
44064ab3302SCarolineConcatto     const char *&, enum FortranRounding);
441b7a5b5c7Speter klausler template ConversionToBinaryResult<113> ConvertToBinary<113>(
44264ab3302SCarolineConcatto     const char *&, enum FortranRounding);
44364ab3302SCarolineConcatto 
44464ab3302SCarolineConcatto extern "C" {
44564ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToFloat(
44664ab3302SCarolineConcatto     const char **p, float *f, enum FortranRounding rounding) {
44764ab3302SCarolineConcatto   auto result{Fortran::decimal::ConvertToBinary<24>(*p, rounding)};
44864ab3302SCarolineConcatto   std::memcpy(reinterpret_cast<void *>(f),
44964ab3302SCarolineConcatto       reinterpret_cast<const void *>(&result.binary), sizeof *f);
45064ab3302SCarolineConcatto   return result.flags;
45164ab3302SCarolineConcatto }
45264ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToDouble(
45364ab3302SCarolineConcatto     const char **p, double *d, enum FortranRounding rounding) {
45464ab3302SCarolineConcatto   auto result{Fortran::decimal::ConvertToBinary<53>(*p, rounding)};
45564ab3302SCarolineConcatto   std::memcpy(reinterpret_cast<void *>(d),
45664ab3302SCarolineConcatto       reinterpret_cast<const void *>(&result.binary), sizeof *d);
45764ab3302SCarolineConcatto   return result.flags;
45864ab3302SCarolineConcatto }
45964ab3302SCarolineConcatto #if __x86_64__ && !defined(_MSC_VER)
46064ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToLongDouble(
46164ab3302SCarolineConcatto     const char **p, long double *ld, enum FortranRounding rounding) {
46264ab3302SCarolineConcatto   auto result{Fortran::decimal::ConvertToBinary<64>(*p, rounding)};
46364ab3302SCarolineConcatto   std::memcpy(reinterpret_cast<void *>(ld),
46464ab3302SCarolineConcatto       reinterpret_cast<const void *>(&result.binary), sizeof *ld);
46564ab3302SCarolineConcatto   return result.flags;
46664ab3302SCarolineConcatto }
46764ab3302SCarolineConcatto #endif
46864ab3302SCarolineConcatto }
4691f879005STim Keith } // namespace Fortran::decimal
470