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( 22da25f968SPeter Klausler const char *&p, bool &inexact, const char *end) { 2364ab3302SCarolineConcatto SetToZero(); 24da25f968SPeter Klausler if (end && p >= end) { 25da25f968SPeter Klausler return false; 26da25f968SPeter Klausler } 27da25f968SPeter Klausler // Skip leading spaces 28da25f968SPeter Klausler for (; p != end && *p == ' '; ++p) { 29da25f968SPeter Klausler } 30da25f968SPeter Klausler if (p == end) { 31da25f968SPeter Klausler return false; 3264ab3302SCarolineConcatto } 3364ab3302SCarolineConcatto const char *q{p}; 3464ab3302SCarolineConcatto isNegative_ = *q == '-'; 3564ab3302SCarolineConcatto if (*q == '-' || *q == '+') { 3664ab3302SCarolineConcatto ++q; 3764ab3302SCarolineConcatto } 3864ab3302SCarolineConcatto const char *start{q}; 39da25f968SPeter Klausler for (; q != end && *q == '0'; ++q) { 4064ab3302SCarolineConcatto } 41da25f968SPeter Klausler const char *firstDigit{q}; 42da25f968SPeter Klausler for (; q != end && *q >= '0' && *q <= '9'; ++q) { 4364ab3302SCarolineConcatto } 4464ab3302SCarolineConcatto const char *point{nullptr}; 45da25f968SPeter Klausler if (q != end && *q == '.') { 4664ab3302SCarolineConcatto point = q; 47da25f968SPeter Klausler for (++q; q != end && *q >= '0' && *q <= '9'; ++q) { 4864ab3302SCarolineConcatto } 4964ab3302SCarolineConcatto } 50da25f968SPeter Klausler if (q == start || (q == start + 1 && start == point)) { 5164ab3302SCarolineConcatto return false; // require at least one digit 5264ab3302SCarolineConcatto } 5364ab3302SCarolineConcatto // There's a valid number here; set the reference argument to point to 54da25f968SPeter Klausler // the first character afterward, which might be an exponent part. 5564ab3302SCarolineConcatto p = q; 5664ab3302SCarolineConcatto // Strip off trailing zeroes 5764ab3302SCarolineConcatto if (point) { 5864ab3302SCarolineConcatto while (q[-1] == '0') { 5964ab3302SCarolineConcatto --q; 6064ab3302SCarolineConcatto } 6164ab3302SCarolineConcatto if (q[-1] == '.') { 6264ab3302SCarolineConcatto point = nullptr; 6364ab3302SCarolineConcatto --q; 6464ab3302SCarolineConcatto } 6564ab3302SCarolineConcatto } 6664ab3302SCarolineConcatto if (!point) { 67da25f968SPeter Klausler while (q > firstDigit && q[-1] == '0') { 6864ab3302SCarolineConcatto --q; 6964ab3302SCarolineConcatto ++exponent_; 7064ab3302SCarolineConcatto } 7164ab3302SCarolineConcatto } 7264ab3302SCarolineConcatto // Trim any excess digits 73da25f968SPeter Klausler const char *limit{firstDigit + maxDigits * log10Radix + (point != nullptr)}; 7464ab3302SCarolineConcatto if (q > limit) { 7564ab3302SCarolineConcatto inexact = true; 7664ab3302SCarolineConcatto if (point >= limit) { 7764ab3302SCarolineConcatto q = point; 7864ab3302SCarolineConcatto point = nullptr; 7964ab3302SCarolineConcatto } 8064ab3302SCarolineConcatto if (!point) { 8164ab3302SCarolineConcatto exponent_ += q - limit; 8264ab3302SCarolineConcatto } 8364ab3302SCarolineConcatto q = limit; 8464ab3302SCarolineConcatto } 8564ab3302SCarolineConcatto if (point) { 8664ab3302SCarolineConcatto exponent_ -= static_cast<int>(q - point - 1); 8764ab3302SCarolineConcatto } 88da25f968SPeter Klausler if (q == firstDigit) { 8964ab3302SCarolineConcatto exponent_ = 0; // all zeros 9064ab3302SCarolineConcatto } 9164ab3302SCarolineConcatto // Rack the decimal digits up into big Digits. 92da25f968SPeter Klausler for (auto times{radix}; q-- > firstDigit;) { 9364ab3302SCarolineConcatto if (*q != '.') { 9464ab3302SCarolineConcatto if (times == radix) { 9564ab3302SCarolineConcatto digit_[digits_++] = *q - '0'; 9664ab3302SCarolineConcatto times = 10; 9764ab3302SCarolineConcatto } else { 9864ab3302SCarolineConcatto digit_[digits_ - 1] += times * (*q - '0'); 9964ab3302SCarolineConcatto times *= 10; 10064ab3302SCarolineConcatto } 10164ab3302SCarolineConcatto } 10264ab3302SCarolineConcatto } 10364ab3302SCarolineConcatto // Look for an optional exponent field. 104da25f968SPeter Klausler if (p == end) { 105da25f968SPeter Klausler return true; 106da25f968SPeter Klausler } 10764ab3302SCarolineConcatto q = p; 10864ab3302SCarolineConcatto switch (*q) { 10964ab3302SCarolineConcatto case 'e': 11064ab3302SCarolineConcatto case 'E': 11164ab3302SCarolineConcatto case 'd': 11264ab3302SCarolineConcatto case 'D': 11364ab3302SCarolineConcatto case 'q': 11464ab3302SCarolineConcatto case 'Q': { 115da25f968SPeter Klausler if (++q == end) { 116da25f968SPeter Klausler break; 117da25f968SPeter Klausler } 118da25f968SPeter Klausler bool negExpo{*q == '-'}; 11964ab3302SCarolineConcatto if (*q == '-' || *q == '+') { 12064ab3302SCarolineConcatto ++q; 12164ab3302SCarolineConcatto } 122da25f968SPeter Klausler if (q != end && *q >= '0' && *q <= '9') { 12364ab3302SCarolineConcatto int expo{0}; 124da25f968SPeter Klausler for (; q != end && *q == '0'; ++q) { 12564ab3302SCarolineConcatto } 12664ab3302SCarolineConcatto const char *expDig{q}; 127da25f968SPeter Klausler for (; q != end && *q >= '0' && *q <= '9'; ++q) { 128da25f968SPeter Klausler expo = 10 * expo + *q - '0'; 12964ab3302SCarolineConcatto } 13064ab3302SCarolineConcatto if (q >= expDig + 8) { 13164ab3302SCarolineConcatto // There's a ridiculous number of nonzero exponent digits. 13264ab3302SCarolineConcatto // The decimal->binary conversion routine will cope with 13364ab3302SCarolineConcatto // returning 0 or Inf, but we must ensure that "expo" didn't 13464ab3302SCarolineConcatto // overflow back around to something legal. 13564ab3302SCarolineConcatto expo = 10 * Real::decimalRange; 13664ab3302SCarolineConcatto exponent_ = 0; 13764ab3302SCarolineConcatto } 138da25f968SPeter Klausler p = q; // exponent is valid; advance the termination pointer 13964ab3302SCarolineConcatto if (negExpo) { 14064ab3302SCarolineConcatto exponent_ -= expo; 14164ab3302SCarolineConcatto } else { 14264ab3302SCarolineConcatto exponent_ += expo; 14364ab3302SCarolineConcatto } 14464ab3302SCarolineConcatto } 14564ab3302SCarolineConcatto } break; 1461f879005STim Keith default: 1471f879005STim Keith break; 14864ab3302SCarolineConcatto } 14964ab3302SCarolineConcatto return true; 15064ab3302SCarolineConcatto } 15164ab3302SCarolineConcatto 1526fec2c44Speter klausler template <int PREC, int LOG10RADIX> 1536fec2c44Speter klausler void BigRadixFloatingPointNumber<PREC, 1546fec2c44Speter klausler LOG10RADIX>::LoseLeastSignificantDigit() { 1556fec2c44Speter klausler Digit LSD{digit_[0]}; 1566fec2c44Speter klausler for (int j{0}; j < digits_ - 1; ++j) { 1576fec2c44Speter klausler digit_[j] = digit_[j + 1]; 1586fec2c44Speter klausler } 1596fec2c44Speter klausler digit_[digits_ - 1] = 0; 1606fec2c44Speter klausler bool incr{false}; 1616fec2c44Speter klausler switch (rounding_) { 1626fec2c44Speter klausler case RoundNearest: 1636fec2c44Speter klausler incr = LSD > radix / 2 || (LSD == radix / 2 && digit_[0] % 2 != 0); 1646fec2c44Speter klausler break; 1656fec2c44Speter klausler case RoundUp: 1666fec2c44Speter klausler incr = LSD > 0 && !isNegative_; 1676fec2c44Speter klausler break; 1686fec2c44Speter klausler case RoundDown: 1696fec2c44Speter klausler incr = LSD > 0 && isNegative_; 1706fec2c44Speter klausler break; 1716fec2c44Speter klausler case RoundToZero: 1726fec2c44Speter klausler break; 1736fec2c44Speter klausler case RoundCompatible: 1746fec2c44Speter klausler incr = LSD >= radix / 2; 1756fec2c44Speter klausler break; 1766fec2c44Speter klausler } 1776fec2c44Speter klausler for (int j{0}; (digit_[j] += incr) == radix; ++j) { 1786fec2c44Speter klausler digit_[j] = 0; 1796fec2c44Speter klausler } 1806fec2c44Speter klausler } 1816fec2c44Speter klausler 18264ab3302SCarolineConcatto // This local utility class represents an unrounded nonnegative 18364ab3302SCarolineConcatto // binary floating-point value with an unbiased (i.e., signed) 18464ab3302SCarolineConcatto // binary exponent, an integer value (not a fraction) with an implied 18564ab3302SCarolineConcatto // binary point to its *right*, and some guard bits for rounding. 18664ab3302SCarolineConcatto template <int PREC> class IntermediateFloat { 18764ab3302SCarolineConcatto public: 18864ab3302SCarolineConcatto static constexpr int precision{PREC}; 18964ab3302SCarolineConcatto using IntType = common::HostUnsignedIntType<precision>; 19064ab3302SCarolineConcatto static constexpr IntType topBit{IntType{1} << (precision - 1)}; 19164ab3302SCarolineConcatto static constexpr IntType mask{topBit + (topBit - 1)}; 19264ab3302SCarolineConcatto 19364ab3302SCarolineConcatto IntermediateFloat() {} 19464ab3302SCarolineConcatto IntermediateFloat(const IntermediateFloat &) = default; 19564ab3302SCarolineConcatto 19664ab3302SCarolineConcatto // Assumes that exponent_ is valid on entry, and may increment it. 19764ab3302SCarolineConcatto // Returns the number of guard_ bits that have been determined. 19864ab3302SCarolineConcatto template <typename UINT> bool SetTo(UINT n) { 19964ab3302SCarolineConcatto static constexpr int nBits{CHAR_BIT * sizeof n}; 20064ab3302SCarolineConcatto if constexpr (precision >= nBits) { 20164ab3302SCarolineConcatto value_ = n; 20264ab3302SCarolineConcatto guard_ = 0; 20364ab3302SCarolineConcatto return 0; 20464ab3302SCarolineConcatto } else { 20564ab3302SCarolineConcatto int shift{common::BitsNeededFor(n) - precision}; 20664ab3302SCarolineConcatto if (shift <= 0) { 20764ab3302SCarolineConcatto value_ = n; 20864ab3302SCarolineConcatto guard_ = 0; 20964ab3302SCarolineConcatto return 0; 21064ab3302SCarolineConcatto } else { 21164ab3302SCarolineConcatto value_ = n >> shift; 21264ab3302SCarolineConcatto exponent_ += shift; 21364ab3302SCarolineConcatto n <<= nBits - shift; 21464ab3302SCarolineConcatto guard_ = (n >> (nBits - guardBits)) | ((n << guardBits) != 0); 21564ab3302SCarolineConcatto return shift; 21664ab3302SCarolineConcatto } 21764ab3302SCarolineConcatto } 21864ab3302SCarolineConcatto } 21964ab3302SCarolineConcatto 22064ab3302SCarolineConcatto void ShiftIn(int bit = 0) { value_ = value_ + value_ + bit; } 22164ab3302SCarolineConcatto bool IsFull() const { return value_ >= topBit; } 22264ab3302SCarolineConcatto void AdjustExponent(int by) { exponent_ += by; } 22364ab3302SCarolineConcatto void SetGuard(int g) { 22464ab3302SCarolineConcatto guard_ |= (static_cast<GuardType>(g & 6) << (guardBits - 3)) | (g & 1); 22564ab3302SCarolineConcatto } 22664ab3302SCarolineConcatto 22764ab3302SCarolineConcatto ConversionToBinaryResult<PREC> ToBinary( 22864ab3302SCarolineConcatto bool isNegative, FortranRounding) const; 22964ab3302SCarolineConcatto 23064ab3302SCarolineConcatto private: 23164ab3302SCarolineConcatto static constexpr int guardBits{3}; // guard, round, sticky 23264ab3302SCarolineConcatto using GuardType = int; 23364ab3302SCarolineConcatto static constexpr GuardType oneHalf{GuardType{1} << (guardBits - 1)}; 23464ab3302SCarolineConcatto 23564ab3302SCarolineConcatto IntType value_{0}; 23664ab3302SCarolineConcatto GuardType guard_{0}; 23764ab3302SCarolineConcatto int exponent_{0}; 23864ab3302SCarolineConcatto }; 23964ab3302SCarolineConcatto 24064ab3302SCarolineConcatto template <int PREC> 24164ab3302SCarolineConcatto ConversionToBinaryResult<PREC> IntermediateFloat<PREC>::ToBinary( 24264ab3302SCarolineConcatto bool isNegative, FortranRounding rounding) const { 24364ab3302SCarolineConcatto using Binary = BinaryFloatingPointNumber<PREC>; 24464ab3302SCarolineConcatto // Create a fraction with a binary point to the left of the integer 24564ab3302SCarolineConcatto // value_, and bias the exponent. 24664ab3302SCarolineConcatto IntType fraction{value_}; 24764ab3302SCarolineConcatto GuardType guard{guard_}; 24864ab3302SCarolineConcatto int expo{exponent_ + Binary::exponentBias + (precision - 1)}; 24964ab3302SCarolineConcatto while (expo < 1 && (fraction > 0 || guard > oneHalf)) { 25064ab3302SCarolineConcatto guard = (guard & 1) | (guard >> 1) | 25164ab3302SCarolineConcatto ((static_cast<GuardType>(fraction) & 1) << (guardBits - 1)); 25264ab3302SCarolineConcatto fraction >>= 1; 25364ab3302SCarolineConcatto ++expo; 25464ab3302SCarolineConcatto } 25564ab3302SCarolineConcatto int flags{Exact}; 25664ab3302SCarolineConcatto if (guard != 0) { 25764ab3302SCarolineConcatto flags |= Inexact; 25864ab3302SCarolineConcatto } 25964ab3302SCarolineConcatto if (fraction == 0 && guard <= oneHalf) { 26064ab3302SCarolineConcatto return {Binary{}, static_cast<enum ConversionResultFlags>(flags)}; 26164ab3302SCarolineConcatto } 26264ab3302SCarolineConcatto // The value is nonzero; normalize it. 26364ab3302SCarolineConcatto while (fraction < topBit && expo > 1) { 26464ab3302SCarolineConcatto --expo; 26564ab3302SCarolineConcatto fraction = fraction * 2 + (guard >> (guardBits - 2)); 26664ab3302SCarolineConcatto guard = (((guard >> (guardBits - 2)) & 1) << (guardBits - 1)) | (guard & 1); 26764ab3302SCarolineConcatto } 26864ab3302SCarolineConcatto // Apply rounding 26964ab3302SCarolineConcatto bool incr{false}; 27064ab3302SCarolineConcatto switch (rounding) { 27164ab3302SCarolineConcatto case RoundNearest: 27264ab3302SCarolineConcatto incr = guard > oneHalf || (guard == oneHalf && (fraction & 1)); 27364ab3302SCarolineConcatto break; 2741f879005STim Keith case RoundUp: 2751f879005STim Keith incr = guard != 0 && !isNegative; 2761f879005STim Keith break; 2771f879005STim Keith case RoundDown: 2781f879005STim Keith incr = guard != 0 && isNegative; 2791f879005STim Keith break; 2801f879005STim Keith case RoundToZero: 2811f879005STim Keith break; 2821f879005STim Keith case RoundCompatible: 2831f879005STim Keith incr = guard >= oneHalf; 2841f879005STim Keith break; 28564ab3302SCarolineConcatto } 28664ab3302SCarolineConcatto if (incr) { 28764ab3302SCarolineConcatto if (fraction == mask) { 28864ab3302SCarolineConcatto // rounding causes a carry 28964ab3302SCarolineConcatto ++expo; 29064ab3302SCarolineConcatto fraction = topBit; 29164ab3302SCarolineConcatto } else { 29264ab3302SCarolineConcatto ++fraction; 29364ab3302SCarolineConcatto } 29464ab3302SCarolineConcatto } 29564ab3302SCarolineConcatto if (expo == 1 && fraction < topBit) { 29664ab3302SCarolineConcatto expo = 0; // subnormal 29764ab3302SCarolineConcatto } 29864ab3302SCarolineConcatto if (expo >= Binary::maxExponent) { 29964ab3302SCarolineConcatto expo = Binary::maxExponent; // Inf 30064ab3302SCarolineConcatto flags |= Overflow; 30164ab3302SCarolineConcatto fraction = 0; 30264ab3302SCarolineConcatto } 30364ab3302SCarolineConcatto using Raw = typename Binary::RawType; 30464ab3302SCarolineConcatto Raw raw = static_cast<Raw>(isNegative) << (Binary::bits - 1); 30564ab3302SCarolineConcatto raw |= static_cast<Raw>(expo) << Binary::significandBits; 30664ab3302SCarolineConcatto if constexpr (Binary::isImplicitMSB) { 30764ab3302SCarolineConcatto fraction &= ~topBit; 30864ab3302SCarolineConcatto } 30964ab3302SCarolineConcatto raw |= fraction; 31064ab3302SCarolineConcatto return {Binary(raw), static_cast<enum ConversionResultFlags>(flags)}; 31164ab3302SCarolineConcatto } 31264ab3302SCarolineConcatto 31364ab3302SCarolineConcatto template <int PREC, int LOG10RADIX> 31464ab3302SCarolineConcatto ConversionToBinaryResult<PREC> 31564ab3302SCarolineConcatto BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary() { 31664ab3302SCarolineConcatto // On entry, *this holds a multi-precision integer value in a radix of a 31764ab3302SCarolineConcatto // large power of ten. Its radix point is defined to be to the right of its 31864ab3302SCarolineConcatto // digits, and "exponent_" is the power of ten by which it is to be scaled. 31964ab3302SCarolineConcatto Normalize(); 32064ab3302SCarolineConcatto if (digits_ == 0) { // zero value 32164ab3302SCarolineConcatto return {Real{SignBit()}}; 32264ab3302SCarolineConcatto } 32364ab3302SCarolineConcatto // The value is not zero: x = D. * 10.**E 32464ab3302SCarolineConcatto // Shift our perspective on the radix (& decimal) point so that 32564ab3302SCarolineConcatto // it sits to the *left* of the digits: i.e., x = .D * 10.**E 32664ab3302SCarolineConcatto exponent_ += digits_ * log10Radix; 32764ab3302SCarolineConcatto // Sanity checks for ridiculous exponents 32864ab3302SCarolineConcatto static constexpr int crazy{2 * Real::decimalRange + log10Radix}; 32964ab3302SCarolineConcatto if (exponent_ < -crazy) { // underflow to +/-0. 33064ab3302SCarolineConcatto return {Real{SignBit()}, Inexact}; 33164ab3302SCarolineConcatto } else if (exponent_ > crazy) { // overflow to +/-Inf. 33264ab3302SCarolineConcatto return {Real{Infinity()}, Overflow}; 33364ab3302SCarolineConcatto } 33464ab3302SCarolineConcatto // Apply any negative decimal exponent by multiplication 33564ab3302SCarolineConcatto // by a power of two, adjusting the binary exponent to compensate. 33664ab3302SCarolineConcatto IntermediateFloat<PREC> f; 33764ab3302SCarolineConcatto while (exponent_ < log10Radix) { 33864ab3302SCarolineConcatto // x = 0.D * 10.**E * 2.**(f.ex) -> 512 * 0.D * 10.**E * 2.**(f.ex-9) 33964ab3302SCarolineConcatto f.AdjustExponent(-9); 34064ab3302SCarolineConcatto digitLimit_ = digits_; 34164ab3302SCarolineConcatto if (int carry{MultiplyWithoutNormalization<512>()}) { 34264ab3302SCarolineConcatto // x = c.D * 10.**E * 2.**(f.ex) -> .cD * 10.**(E+16) * 2.**(f.ex) 34364ab3302SCarolineConcatto PushCarry(carry); 34464ab3302SCarolineConcatto exponent_ += log10Radix; 34564ab3302SCarolineConcatto } 34664ab3302SCarolineConcatto } 34764ab3302SCarolineConcatto // Apply any positive decimal exponent greater than 34864ab3302SCarolineConcatto // is needed to treat the topmost digit as an integer 34964ab3302SCarolineConcatto // part by multiplying by 10 or 10000 repeatedly. 35064ab3302SCarolineConcatto while (exponent_ > log10Radix) { 35164ab3302SCarolineConcatto digitLimit_ = digits_; 35264ab3302SCarolineConcatto int carry; 35364ab3302SCarolineConcatto if (exponent_ >= log10Radix + 4) { 35464ab3302SCarolineConcatto // x = 0.D * 10.**E * 2.**(f.ex) -> 625 * .D * 10.**(E-4) * 2.**(f.ex+4) 35564ab3302SCarolineConcatto exponent_ -= 4; 35664ab3302SCarolineConcatto carry = MultiplyWithoutNormalization<(5 * 5 * 5 * 5)>(); 35764ab3302SCarolineConcatto f.AdjustExponent(4); 35864ab3302SCarolineConcatto } else { 35964ab3302SCarolineConcatto // x = 0.D * 10.**E * 2.**(f.ex) -> 5 * .D * 10.**(E-1) * 2.**(f.ex+1) 36064ab3302SCarolineConcatto --exponent_; 36164ab3302SCarolineConcatto carry = MultiplyWithoutNormalization<5>(); 36264ab3302SCarolineConcatto f.AdjustExponent(1); 36364ab3302SCarolineConcatto } 36464ab3302SCarolineConcatto if (carry != 0) { 36564ab3302SCarolineConcatto // x = c.D * 10.**E * 2.**(f.ex) -> .cD * 10.**(E+16) * 2.**(f.ex) 36664ab3302SCarolineConcatto PushCarry(carry); 36764ab3302SCarolineConcatto exponent_ += log10Radix; 36864ab3302SCarolineConcatto } 36964ab3302SCarolineConcatto } 37064ab3302SCarolineConcatto // So exponent_ is now log10Radix, meaning that the 37164ab3302SCarolineConcatto // MSD can be taken as an integer part and transferred 37264ab3302SCarolineConcatto // to the binary result. 37364ab3302SCarolineConcatto // x = .jD * 10.**16 * 2.**(f.ex) -> .D * j * 2.**(f.ex) 37464ab3302SCarolineConcatto int guardShift{f.SetTo(digit_[--digits_])}; 37564ab3302SCarolineConcatto // Transfer additional bits until the result is normal. 37664ab3302SCarolineConcatto digitLimit_ = digits_; 37764ab3302SCarolineConcatto while (!f.IsFull()) { 37864ab3302SCarolineConcatto // x = ((b.D)/2) * j * 2.**(f.ex) -> .D * (2j + b) * 2.**(f.ex-1) 37964ab3302SCarolineConcatto f.AdjustExponent(-1); 38064ab3302SCarolineConcatto std::uint32_t carry = MultiplyWithoutNormalization<2>(); 38164ab3302SCarolineConcatto f.ShiftIn(carry); 38264ab3302SCarolineConcatto } 38364ab3302SCarolineConcatto // Get the next few bits for rounding. Allow for some guard bits 38464ab3302SCarolineConcatto // that may have already been set in f.SetTo() above. 38564ab3302SCarolineConcatto int guard{0}; 38664ab3302SCarolineConcatto if (guardShift == 0) { 38764ab3302SCarolineConcatto guard = MultiplyWithoutNormalization<4>(); 38864ab3302SCarolineConcatto } else if (guardShift == 1) { 38964ab3302SCarolineConcatto guard = MultiplyWithoutNormalization<2>(); 39064ab3302SCarolineConcatto } 39164ab3302SCarolineConcatto guard = guard + guard + !IsZero(); 39264ab3302SCarolineConcatto f.SetGuard(guard); 39364ab3302SCarolineConcatto return f.ToBinary(isNegative_, rounding_); 39464ab3302SCarolineConcatto } 39564ab3302SCarolineConcatto 39664ab3302SCarolineConcatto template <int PREC, int LOG10RADIX> 39764ab3302SCarolineConcatto ConversionToBinaryResult<PREC> 398da25f968SPeter Klausler BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary( 399da25f968SPeter Klausler const char *&p, const char *limit) { 40064ab3302SCarolineConcatto bool inexact{false}; 401da25f968SPeter Klausler if (ParseNumber(p, inexact, limit)) { 40264ab3302SCarolineConcatto auto result{ConvertToBinary()}; 40364ab3302SCarolineConcatto if (inexact) { 40464ab3302SCarolineConcatto result.flags = 40564ab3302SCarolineConcatto static_cast<enum ConversionResultFlags>(result.flags | Inexact); 40664ab3302SCarolineConcatto } 40764ab3302SCarolineConcatto return result; 40864ab3302SCarolineConcatto } else { 40964ab3302SCarolineConcatto // Could not parse a decimal floating-point number. p has been 41064ab3302SCarolineConcatto // advanced over any leading spaces. 411*f1dbf8e4SPeter Klausler if ((!limit || limit >= p + 3) && toupper(p[0]) == 'N' && 412*f1dbf8e4SPeter Klausler toupper(p[1]) == 'A' && toupper(p[2]) == 'N') { 41364ab3302SCarolineConcatto // NaN 41464ab3302SCarolineConcatto p += 3; 415*f1dbf8e4SPeter Klausler if ((!limit || p < limit) && *p == '(') { 416*f1dbf8e4SPeter Klausler int depth{1}; 417*f1dbf8e4SPeter Klausler do { 418*f1dbf8e4SPeter Klausler ++p; 419*f1dbf8e4SPeter Klausler if (limit && p >= limit) { 420*f1dbf8e4SPeter Klausler // Invalid input 421*f1dbf8e4SPeter Klausler return {Real{NaN()}, Invalid}; 422*f1dbf8e4SPeter Klausler } else if (*p == '(') { 423*f1dbf8e4SPeter Klausler ++depth; 424*f1dbf8e4SPeter Klausler } else if (*p == ')') { 425*f1dbf8e4SPeter Klausler --depth; 426*f1dbf8e4SPeter Klausler } 427*f1dbf8e4SPeter Klausler } while (depth > 0); 428*f1dbf8e4SPeter Klausler ++p; 429*f1dbf8e4SPeter Klausler } 43064ab3302SCarolineConcatto return {Real{NaN()}}; 43164ab3302SCarolineConcatto } else { 43264ab3302SCarolineConcatto // Try to parse Inf, maybe with a sign 43364ab3302SCarolineConcatto const char *q{p}; 434*f1dbf8e4SPeter Klausler if (!limit || q < limit) { 43564ab3302SCarolineConcatto isNegative_ = *q == '-'; 436*f1dbf8e4SPeter Klausler if (isNegative_ || *q == '+') { 43764ab3302SCarolineConcatto ++q; 43864ab3302SCarolineConcatto } 439*f1dbf8e4SPeter Klausler } 440*f1dbf8e4SPeter Klausler if ((!limit || limit >= q + 3) && toupper(q[0]) == 'I' && 441*f1dbf8e4SPeter Klausler toupper(q[1]) == 'N' && toupper(q[2]) == 'F') { 44264ab3302SCarolineConcatto p = q + 3; 44364ab3302SCarolineConcatto return {Real{Infinity()}}; 44464ab3302SCarolineConcatto } else { 44564ab3302SCarolineConcatto // Invalid input 44664ab3302SCarolineConcatto return {Real{NaN()}, Invalid}; 44764ab3302SCarolineConcatto } 44864ab3302SCarolineConcatto } 44964ab3302SCarolineConcatto } 45064ab3302SCarolineConcatto } 45164ab3302SCarolineConcatto 45264ab3302SCarolineConcatto template <int PREC> 45364ab3302SCarolineConcatto ConversionToBinaryResult<PREC> ConvertToBinary( 454da25f968SPeter Klausler const char *&p, enum FortranRounding rounding, const char *end) { 455da25f968SPeter Klausler return BigRadixFloatingPointNumber<PREC>{rounding}.ConvertToBinary(p, end); 45664ab3302SCarolineConcatto } 45764ab3302SCarolineConcatto 45864ab3302SCarolineConcatto template ConversionToBinaryResult<8> ConvertToBinary<8>( 459da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end); 46064ab3302SCarolineConcatto template ConversionToBinaryResult<11> ConvertToBinary<11>( 461da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end); 46264ab3302SCarolineConcatto template ConversionToBinaryResult<24> ConvertToBinary<24>( 463da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end); 46464ab3302SCarolineConcatto template ConversionToBinaryResult<53> ConvertToBinary<53>( 465da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end); 46664ab3302SCarolineConcatto template ConversionToBinaryResult<64> ConvertToBinary<64>( 467da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end); 468b7a5b5c7Speter klausler template ConversionToBinaryResult<113> ConvertToBinary<113>( 469da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end); 47064ab3302SCarolineConcatto 47164ab3302SCarolineConcatto extern "C" { 47264ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToFloat( 47364ab3302SCarolineConcatto const char **p, float *f, enum FortranRounding rounding) { 47464ab3302SCarolineConcatto auto result{Fortran::decimal::ConvertToBinary<24>(*p, rounding)}; 47564ab3302SCarolineConcatto std::memcpy(reinterpret_cast<void *>(f), 47664ab3302SCarolineConcatto reinterpret_cast<const void *>(&result.binary), sizeof *f); 47764ab3302SCarolineConcatto return result.flags; 47864ab3302SCarolineConcatto } 47964ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToDouble( 48064ab3302SCarolineConcatto const char **p, double *d, enum FortranRounding rounding) { 48164ab3302SCarolineConcatto auto result{Fortran::decimal::ConvertToBinary<53>(*p, rounding)}; 48264ab3302SCarolineConcatto std::memcpy(reinterpret_cast<void *>(d), 48364ab3302SCarolineConcatto reinterpret_cast<const void *>(&result.binary), sizeof *d); 48464ab3302SCarolineConcatto return result.flags; 48564ab3302SCarolineConcatto } 48664ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToLongDouble( 48764ab3302SCarolineConcatto const char **p, long double *ld, enum FortranRounding rounding) { 48864ab3302SCarolineConcatto auto result{Fortran::decimal::ConvertToBinary<64>(*p, rounding)}; 48964ab3302SCarolineConcatto std::memcpy(reinterpret_cast<void *>(ld), 49064ab3302SCarolineConcatto reinterpret_cast<const void *>(&result.binary), sizeof *ld); 49164ab3302SCarolineConcatto return result.flags; 49264ab3302SCarolineConcatto } 49364ab3302SCarolineConcatto } 4941f879005STim Keith } // namespace Fortran::decimal 495