1*64ab3302SCarolineConcatto //===-- lib/Decimal/decimal-to-binary.cpp ---------------------------------===// 2*64ab3302SCarolineConcatto // 3*64ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*64ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information. 5*64ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*64ab3302SCarolineConcatto // 7*64ab3302SCarolineConcatto //===----------------------------------------------------------------------===// 8*64ab3302SCarolineConcatto 9*64ab3302SCarolineConcatto #include "big-radix-floating-point.h" 10*64ab3302SCarolineConcatto #include "flang/Common/bit-population-count.h" 11*64ab3302SCarolineConcatto #include "flang/Common/leading-zero-bit-count.h" 12*64ab3302SCarolineConcatto #include "flang/Decimal/binary-floating-point.h" 13*64ab3302SCarolineConcatto #include "flang/Decimal/decimal.h" 14*64ab3302SCarolineConcatto #include <cinttypes> 15*64ab3302SCarolineConcatto #include <cstring> 16*64ab3302SCarolineConcatto #include <ctype.h> 17*64ab3302SCarolineConcatto 18*64ab3302SCarolineConcatto namespace Fortran::decimal { 19*64ab3302SCarolineConcatto 20*64ab3302SCarolineConcatto template<int PREC, int LOG10RADIX> 21*64ab3302SCarolineConcatto bool BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ParseNumber( 22*64ab3302SCarolineConcatto const char *&p, bool &inexact) { 23*64ab3302SCarolineConcatto SetToZero(); 24*64ab3302SCarolineConcatto while (*p == ' ') { 25*64ab3302SCarolineConcatto ++p; 26*64ab3302SCarolineConcatto } 27*64ab3302SCarolineConcatto const char *q{p}; 28*64ab3302SCarolineConcatto isNegative_ = *q == '-'; 29*64ab3302SCarolineConcatto if (*q == '-' || *q == '+') { 30*64ab3302SCarolineConcatto ++q; 31*64ab3302SCarolineConcatto } 32*64ab3302SCarolineConcatto const char *start{q}; 33*64ab3302SCarolineConcatto while (*q == '0') { 34*64ab3302SCarolineConcatto ++q; 35*64ab3302SCarolineConcatto } 36*64ab3302SCarolineConcatto const char *first{q}; 37*64ab3302SCarolineConcatto for (; *q >= '0' && *q <= '9'; ++q) { 38*64ab3302SCarolineConcatto } 39*64ab3302SCarolineConcatto const char *point{nullptr}; 40*64ab3302SCarolineConcatto if (*q == '.') { 41*64ab3302SCarolineConcatto point = q; 42*64ab3302SCarolineConcatto for (++q; *q >= '0' && *q <= '9'; ++q) { 43*64ab3302SCarolineConcatto } 44*64ab3302SCarolineConcatto } 45*64ab3302SCarolineConcatto if (q == start || (q == start + 1 && *start == '.')) { 46*64ab3302SCarolineConcatto return false; // require at least one digit 47*64ab3302SCarolineConcatto } 48*64ab3302SCarolineConcatto // There's a valid number here; set the reference argument to point to 49*64ab3302SCarolineConcatto // the first character afterward. 50*64ab3302SCarolineConcatto p = q; 51*64ab3302SCarolineConcatto // Strip off trailing zeroes 52*64ab3302SCarolineConcatto if (point) { 53*64ab3302SCarolineConcatto while (q[-1] == '0') { 54*64ab3302SCarolineConcatto --q; 55*64ab3302SCarolineConcatto } 56*64ab3302SCarolineConcatto if (q[-1] == '.') { 57*64ab3302SCarolineConcatto point = nullptr; 58*64ab3302SCarolineConcatto --q; 59*64ab3302SCarolineConcatto } 60*64ab3302SCarolineConcatto } 61*64ab3302SCarolineConcatto if (!point) { 62*64ab3302SCarolineConcatto while (q > first && q[-1] == '0') { 63*64ab3302SCarolineConcatto --q; 64*64ab3302SCarolineConcatto ++exponent_; 65*64ab3302SCarolineConcatto } 66*64ab3302SCarolineConcatto } 67*64ab3302SCarolineConcatto // Trim any excess digits 68*64ab3302SCarolineConcatto const char *limit{first + maxDigits * log10Radix + (point != nullptr)}; 69*64ab3302SCarolineConcatto if (q > limit) { 70*64ab3302SCarolineConcatto inexact = true; 71*64ab3302SCarolineConcatto if (point >= limit) { 72*64ab3302SCarolineConcatto q = point; 73*64ab3302SCarolineConcatto point = nullptr; 74*64ab3302SCarolineConcatto } 75*64ab3302SCarolineConcatto if (!point) { 76*64ab3302SCarolineConcatto exponent_ += q - limit; 77*64ab3302SCarolineConcatto } 78*64ab3302SCarolineConcatto q = limit; 79*64ab3302SCarolineConcatto } 80*64ab3302SCarolineConcatto if (point) { 81*64ab3302SCarolineConcatto exponent_ -= static_cast<int>(q - point - 1); 82*64ab3302SCarolineConcatto } 83*64ab3302SCarolineConcatto if (q == first) { 84*64ab3302SCarolineConcatto exponent_ = 0; // all zeros 85*64ab3302SCarolineConcatto } 86*64ab3302SCarolineConcatto // Rack the decimal digits up into big Digits. 87*64ab3302SCarolineConcatto for (auto times{radix}; q-- > first;) { 88*64ab3302SCarolineConcatto if (*q != '.') { 89*64ab3302SCarolineConcatto if (times == radix) { 90*64ab3302SCarolineConcatto digit_[digits_++] = *q - '0'; 91*64ab3302SCarolineConcatto times = 10; 92*64ab3302SCarolineConcatto } else { 93*64ab3302SCarolineConcatto digit_[digits_ - 1] += times * (*q - '0'); 94*64ab3302SCarolineConcatto times *= 10; 95*64ab3302SCarolineConcatto } 96*64ab3302SCarolineConcatto } 97*64ab3302SCarolineConcatto } 98*64ab3302SCarolineConcatto // Look for an optional exponent field. 99*64ab3302SCarolineConcatto q = p; 100*64ab3302SCarolineConcatto switch (*q) { 101*64ab3302SCarolineConcatto case 'e': 102*64ab3302SCarolineConcatto case 'E': 103*64ab3302SCarolineConcatto case 'd': 104*64ab3302SCarolineConcatto case 'D': 105*64ab3302SCarolineConcatto case 'q': 106*64ab3302SCarolineConcatto case 'Q': { 107*64ab3302SCarolineConcatto bool negExpo{*++q == '-'}; 108*64ab3302SCarolineConcatto if (*q == '-' || *q == '+') { 109*64ab3302SCarolineConcatto ++q; 110*64ab3302SCarolineConcatto } 111*64ab3302SCarolineConcatto if (*q >= '0' && *q <= '9') { 112*64ab3302SCarolineConcatto int expo{0}; 113*64ab3302SCarolineConcatto while (*q == '0') { 114*64ab3302SCarolineConcatto ++q; 115*64ab3302SCarolineConcatto } 116*64ab3302SCarolineConcatto const char *expDig{q}; 117*64ab3302SCarolineConcatto while (*q >= '0' && *q <= '9') { 118*64ab3302SCarolineConcatto expo = 10 * expo + *q++ - '0'; 119*64ab3302SCarolineConcatto } 120*64ab3302SCarolineConcatto if (q >= expDig + 8) { 121*64ab3302SCarolineConcatto // There's a ridiculous number of nonzero exponent digits. 122*64ab3302SCarolineConcatto // The decimal->binary conversion routine will cope with 123*64ab3302SCarolineConcatto // returning 0 or Inf, but we must ensure that "expo" didn't 124*64ab3302SCarolineConcatto // overflow back around to something legal. 125*64ab3302SCarolineConcatto expo = 10 * Real::decimalRange; 126*64ab3302SCarolineConcatto exponent_ = 0; 127*64ab3302SCarolineConcatto } 128*64ab3302SCarolineConcatto p = q; // exponent was valid 129*64ab3302SCarolineConcatto if (negExpo) { 130*64ab3302SCarolineConcatto exponent_ -= expo; 131*64ab3302SCarolineConcatto } else { 132*64ab3302SCarolineConcatto exponent_ += expo; 133*64ab3302SCarolineConcatto } 134*64ab3302SCarolineConcatto } 135*64ab3302SCarolineConcatto } break; 136*64ab3302SCarolineConcatto default: break; 137*64ab3302SCarolineConcatto } 138*64ab3302SCarolineConcatto return true; 139*64ab3302SCarolineConcatto } 140*64ab3302SCarolineConcatto 141*64ab3302SCarolineConcatto // This local utility class represents an unrounded nonnegative 142*64ab3302SCarolineConcatto // binary floating-point value with an unbiased (i.e., signed) 143*64ab3302SCarolineConcatto // binary exponent, an integer value (not a fraction) with an implied 144*64ab3302SCarolineConcatto // binary point to its *right*, and some guard bits for rounding. 145*64ab3302SCarolineConcatto template<int PREC> class IntermediateFloat { 146*64ab3302SCarolineConcatto public: 147*64ab3302SCarolineConcatto static constexpr int precision{PREC}; 148*64ab3302SCarolineConcatto using IntType = common::HostUnsignedIntType<precision>; 149*64ab3302SCarolineConcatto static constexpr IntType topBit{IntType{1} << (precision - 1)}; 150*64ab3302SCarolineConcatto static constexpr IntType mask{topBit + (topBit - 1)}; 151*64ab3302SCarolineConcatto 152*64ab3302SCarolineConcatto IntermediateFloat() {} 153*64ab3302SCarolineConcatto IntermediateFloat(const IntermediateFloat &) = default; 154*64ab3302SCarolineConcatto 155*64ab3302SCarolineConcatto // Assumes that exponent_ is valid on entry, and may increment it. 156*64ab3302SCarolineConcatto // Returns the number of guard_ bits that have been determined. 157*64ab3302SCarolineConcatto template<typename UINT> bool SetTo(UINT n) { 158*64ab3302SCarolineConcatto static constexpr int nBits{CHAR_BIT * sizeof n}; 159*64ab3302SCarolineConcatto if constexpr (precision >= nBits) { 160*64ab3302SCarolineConcatto value_ = n; 161*64ab3302SCarolineConcatto guard_ = 0; 162*64ab3302SCarolineConcatto return 0; 163*64ab3302SCarolineConcatto } else { 164*64ab3302SCarolineConcatto int shift{common::BitsNeededFor(n) - precision}; 165*64ab3302SCarolineConcatto if (shift <= 0) { 166*64ab3302SCarolineConcatto value_ = n; 167*64ab3302SCarolineConcatto guard_ = 0; 168*64ab3302SCarolineConcatto return 0; 169*64ab3302SCarolineConcatto } else { 170*64ab3302SCarolineConcatto value_ = n >> shift; 171*64ab3302SCarolineConcatto exponent_ += shift; 172*64ab3302SCarolineConcatto n <<= nBits - shift; 173*64ab3302SCarolineConcatto guard_ = (n >> (nBits - guardBits)) | ((n << guardBits) != 0); 174*64ab3302SCarolineConcatto return shift; 175*64ab3302SCarolineConcatto } 176*64ab3302SCarolineConcatto } 177*64ab3302SCarolineConcatto } 178*64ab3302SCarolineConcatto 179*64ab3302SCarolineConcatto void ShiftIn(int bit = 0) { value_ = value_ + value_ + bit; } 180*64ab3302SCarolineConcatto bool IsFull() const { return value_ >= topBit; } 181*64ab3302SCarolineConcatto void AdjustExponent(int by) { exponent_ += by; } 182*64ab3302SCarolineConcatto void SetGuard(int g) { 183*64ab3302SCarolineConcatto guard_ |= (static_cast<GuardType>(g & 6) << (guardBits - 3)) | (g & 1); 184*64ab3302SCarolineConcatto } 185*64ab3302SCarolineConcatto 186*64ab3302SCarolineConcatto ConversionToBinaryResult<PREC> ToBinary( 187*64ab3302SCarolineConcatto bool isNegative, FortranRounding) const; 188*64ab3302SCarolineConcatto 189*64ab3302SCarolineConcatto private: 190*64ab3302SCarolineConcatto static constexpr int guardBits{3}; // guard, round, sticky 191*64ab3302SCarolineConcatto using GuardType = int; 192*64ab3302SCarolineConcatto static constexpr GuardType oneHalf{GuardType{1} << (guardBits - 1)}; 193*64ab3302SCarolineConcatto 194*64ab3302SCarolineConcatto IntType value_{0}; 195*64ab3302SCarolineConcatto GuardType guard_{0}; 196*64ab3302SCarolineConcatto int exponent_{0}; 197*64ab3302SCarolineConcatto }; 198*64ab3302SCarolineConcatto 199*64ab3302SCarolineConcatto template<int PREC> 200*64ab3302SCarolineConcatto ConversionToBinaryResult<PREC> IntermediateFloat<PREC>::ToBinary( 201*64ab3302SCarolineConcatto bool isNegative, FortranRounding rounding) const { 202*64ab3302SCarolineConcatto using Binary = BinaryFloatingPointNumber<PREC>; 203*64ab3302SCarolineConcatto // Create a fraction with a binary point to the left of the integer 204*64ab3302SCarolineConcatto // value_, and bias the exponent. 205*64ab3302SCarolineConcatto IntType fraction{value_}; 206*64ab3302SCarolineConcatto GuardType guard{guard_}; 207*64ab3302SCarolineConcatto int expo{exponent_ + Binary::exponentBias + (precision - 1)}; 208*64ab3302SCarolineConcatto while (expo < 1 && (fraction > 0 || guard > oneHalf)) { 209*64ab3302SCarolineConcatto guard = (guard & 1) | (guard >> 1) | 210*64ab3302SCarolineConcatto ((static_cast<GuardType>(fraction) & 1) << (guardBits - 1)); 211*64ab3302SCarolineConcatto fraction >>= 1; 212*64ab3302SCarolineConcatto ++expo; 213*64ab3302SCarolineConcatto } 214*64ab3302SCarolineConcatto int flags{Exact}; 215*64ab3302SCarolineConcatto if (guard != 0) { 216*64ab3302SCarolineConcatto flags |= Inexact; 217*64ab3302SCarolineConcatto } 218*64ab3302SCarolineConcatto if (fraction == 0 && guard <= oneHalf) { 219*64ab3302SCarolineConcatto return {Binary{}, static_cast<enum ConversionResultFlags>(flags)}; 220*64ab3302SCarolineConcatto } 221*64ab3302SCarolineConcatto // The value is nonzero; normalize it. 222*64ab3302SCarolineConcatto while (fraction < topBit && expo > 1) { 223*64ab3302SCarolineConcatto --expo; 224*64ab3302SCarolineConcatto fraction = fraction * 2 + (guard >> (guardBits - 2)); 225*64ab3302SCarolineConcatto guard = (((guard >> (guardBits - 2)) & 1) << (guardBits - 1)) | (guard & 1); 226*64ab3302SCarolineConcatto } 227*64ab3302SCarolineConcatto // Apply rounding 228*64ab3302SCarolineConcatto bool incr{false}; 229*64ab3302SCarolineConcatto switch (rounding) { 230*64ab3302SCarolineConcatto case RoundNearest: 231*64ab3302SCarolineConcatto case RoundDefault: 232*64ab3302SCarolineConcatto incr = guard > oneHalf || (guard == oneHalf && (fraction & 1)); 233*64ab3302SCarolineConcatto break; 234*64ab3302SCarolineConcatto case RoundUp: incr = guard != 0 && !isNegative; break; 235*64ab3302SCarolineConcatto case RoundDown: incr = guard != 0 && isNegative; break; 236*64ab3302SCarolineConcatto case RoundToZero: break; 237*64ab3302SCarolineConcatto case RoundCompatible: incr = guard >= oneHalf; break; 238*64ab3302SCarolineConcatto } 239*64ab3302SCarolineConcatto if (incr) { 240*64ab3302SCarolineConcatto if (fraction == mask) { 241*64ab3302SCarolineConcatto // rounding causes a carry 242*64ab3302SCarolineConcatto ++expo; 243*64ab3302SCarolineConcatto fraction = topBit; 244*64ab3302SCarolineConcatto } else { 245*64ab3302SCarolineConcatto ++fraction; 246*64ab3302SCarolineConcatto } 247*64ab3302SCarolineConcatto } 248*64ab3302SCarolineConcatto if (expo == 1 && fraction < topBit) { 249*64ab3302SCarolineConcatto expo = 0; // subnormal 250*64ab3302SCarolineConcatto } 251*64ab3302SCarolineConcatto if (expo >= Binary::maxExponent) { 252*64ab3302SCarolineConcatto expo = Binary::maxExponent; // Inf 253*64ab3302SCarolineConcatto flags |= Overflow; 254*64ab3302SCarolineConcatto fraction = 0; 255*64ab3302SCarolineConcatto } 256*64ab3302SCarolineConcatto using Raw = typename Binary::RawType; 257*64ab3302SCarolineConcatto Raw raw = static_cast<Raw>(isNegative) << (Binary::bits - 1); 258*64ab3302SCarolineConcatto raw |= static_cast<Raw>(expo) << Binary::significandBits; 259*64ab3302SCarolineConcatto if constexpr (Binary::isImplicitMSB) { 260*64ab3302SCarolineConcatto fraction &= ~topBit; 261*64ab3302SCarolineConcatto } 262*64ab3302SCarolineConcatto raw |= fraction; 263*64ab3302SCarolineConcatto return {Binary(raw), static_cast<enum ConversionResultFlags>(flags)}; 264*64ab3302SCarolineConcatto } 265*64ab3302SCarolineConcatto 266*64ab3302SCarolineConcatto template<int PREC, int LOG10RADIX> 267*64ab3302SCarolineConcatto ConversionToBinaryResult<PREC> 268*64ab3302SCarolineConcatto BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary() { 269*64ab3302SCarolineConcatto // On entry, *this holds a multi-precision integer value in a radix of a 270*64ab3302SCarolineConcatto // large power of ten. Its radix point is defined to be to the right of its 271*64ab3302SCarolineConcatto // digits, and "exponent_" is the power of ten by which it is to be scaled. 272*64ab3302SCarolineConcatto Normalize(); 273*64ab3302SCarolineConcatto if (digits_ == 0) { // zero value 274*64ab3302SCarolineConcatto return {Real{SignBit()}}; 275*64ab3302SCarolineConcatto } 276*64ab3302SCarolineConcatto // The value is not zero: x = D. * 10.**E 277*64ab3302SCarolineConcatto // Shift our perspective on the radix (& decimal) point so that 278*64ab3302SCarolineConcatto // it sits to the *left* of the digits: i.e., x = .D * 10.**E 279*64ab3302SCarolineConcatto exponent_ += digits_ * log10Radix; 280*64ab3302SCarolineConcatto // Sanity checks for ridiculous exponents 281*64ab3302SCarolineConcatto static constexpr int crazy{2 * Real::decimalRange + log10Radix}; 282*64ab3302SCarolineConcatto if (exponent_ < -crazy) { // underflow to +/-0. 283*64ab3302SCarolineConcatto return {Real{SignBit()}, Inexact}; 284*64ab3302SCarolineConcatto } else if (exponent_ > crazy) { // overflow to +/-Inf. 285*64ab3302SCarolineConcatto return {Real{Infinity()}, Overflow}; 286*64ab3302SCarolineConcatto } 287*64ab3302SCarolineConcatto // Apply any negative decimal exponent by multiplication 288*64ab3302SCarolineConcatto // by a power of two, adjusting the binary exponent to compensate. 289*64ab3302SCarolineConcatto IntermediateFloat<PREC> f; 290*64ab3302SCarolineConcatto while (exponent_ < log10Radix) { 291*64ab3302SCarolineConcatto // x = 0.D * 10.**E * 2.**(f.ex) -> 512 * 0.D * 10.**E * 2.**(f.ex-9) 292*64ab3302SCarolineConcatto f.AdjustExponent(-9); 293*64ab3302SCarolineConcatto digitLimit_ = digits_; 294*64ab3302SCarolineConcatto if (int carry{MultiplyWithoutNormalization<512>()}) { 295*64ab3302SCarolineConcatto // x = c.D * 10.**E * 2.**(f.ex) -> .cD * 10.**(E+16) * 2.**(f.ex) 296*64ab3302SCarolineConcatto PushCarry(carry); 297*64ab3302SCarolineConcatto exponent_ += log10Radix; 298*64ab3302SCarolineConcatto } 299*64ab3302SCarolineConcatto } 300*64ab3302SCarolineConcatto // Apply any positive decimal exponent greater than 301*64ab3302SCarolineConcatto // is needed to treat the topmost digit as an integer 302*64ab3302SCarolineConcatto // part by multiplying by 10 or 10000 repeatedly. 303*64ab3302SCarolineConcatto while (exponent_ > log10Radix) { 304*64ab3302SCarolineConcatto digitLimit_ = digits_; 305*64ab3302SCarolineConcatto int carry; 306*64ab3302SCarolineConcatto if (exponent_ >= log10Radix + 4) { 307*64ab3302SCarolineConcatto // x = 0.D * 10.**E * 2.**(f.ex) -> 625 * .D * 10.**(E-4) * 2.**(f.ex+4) 308*64ab3302SCarolineConcatto exponent_ -= 4; 309*64ab3302SCarolineConcatto carry = MultiplyWithoutNormalization<(5 * 5 * 5 * 5)>(); 310*64ab3302SCarolineConcatto f.AdjustExponent(4); 311*64ab3302SCarolineConcatto } else { 312*64ab3302SCarolineConcatto // x = 0.D * 10.**E * 2.**(f.ex) -> 5 * .D * 10.**(E-1) * 2.**(f.ex+1) 313*64ab3302SCarolineConcatto --exponent_; 314*64ab3302SCarolineConcatto carry = MultiplyWithoutNormalization<5>(); 315*64ab3302SCarolineConcatto f.AdjustExponent(1); 316*64ab3302SCarolineConcatto } 317*64ab3302SCarolineConcatto if (carry != 0) { 318*64ab3302SCarolineConcatto // x = c.D * 10.**E * 2.**(f.ex) -> .cD * 10.**(E+16) * 2.**(f.ex) 319*64ab3302SCarolineConcatto PushCarry(carry); 320*64ab3302SCarolineConcatto exponent_ += log10Radix; 321*64ab3302SCarolineConcatto } 322*64ab3302SCarolineConcatto } 323*64ab3302SCarolineConcatto // So exponent_ is now log10Radix, meaning that the 324*64ab3302SCarolineConcatto // MSD can be taken as an integer part and transferred 325*64ab3302SCarolineConcatto // to the binary result. 326*64ab3302SCarolineConcatto // x = .jD * 10.**16 * 2.**(f.ex) -> .D * j * 2.**(f.ex) 327*64ab3302SCarolineConcatto int guardShift{f.SetTo(digit_[--digits_])}; 328*64ab3302SCarolineConcatto // Transfer additional bits until the result is normal. 329*64ab3302SCarolineConcatto digitLimit_ = digits_; 330*64ab3302SCarolineConcatto while (!f.IsFull()) { 331*64ab3302SCarolineConcatto // x = ((b.D)/2) * j * 2.**(f.ex) -> .D * (2j + b) * 2.**(f.ex-1) 332*64ab3302SCarolineConcatto f.AdjustExponent(-1); 333*64ab3302SCarolineConcatto std::uint32_t carry = MultiplyWithoutNormalization<2>(); 334*64ab3302SCarolineConcatto f.ShiftIn(carry); 335*64ab3302SCarolineConcatto } 336*64ab3302SCarolineConcatto // Get the next few bits for rounding. Allow for some guard bits 337*64ab3302SCarolineConcatto // that may have already been set in f.SetTo() above. 338*64ab3302SCarolineConcatto int guard{0}; 339*64ab3302SCarolineConcatto if (guardShift == 0) { 340*64ab3302SCarolineConcatto guard = MultiplyWithoutNormalization<4>(); 341*64ab3302SCarolineConcatto } else if (guardShift == 1) { 342*64ab3302SCarolineConcatto guard = MultiplyWithoutNormalization<2>(); 343*64ab3302SCarolineConcatto } 344*64ab3302SCarolineConcatto guard = guard + guard + !IsZero(); 345*64ab3302SCarolineConcatto f.SetGuard(guard); 346*64ab3302SCarolineConcatto return f.ToBinary(isNegative_, rounding_); 347*64ab3302SCarolineConcatto } 348*64ab3302SCarolineConcatto 349*64ab3302SCarolineConcatto template<int PREC, int LOG10RADIX> 350*64ab3302SCarolineConcatto ConversionToBinaryResult<PREC> 351*64ab3302SCarolineConcatto BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary(const char *&p) { 352*64ab3302SCarolineConcatto bool inexact{false}; 353*64ab3302SCarolineConcatto if (ParseNumber(p, inexact)) { 354*64ab3302SCarolineConcatto auto result{ConvertToBinary()}; 355*64ab3302SCarolineConcatto if (inexact) { 356*64ab3302SCarolineConcatto result.flags = 357*64ab3302SCarolineConcatto static_cast<enum ConversionResultFlags>(result.flags | Inexact); 358*64ab3302SCarolineConcatto } 359*64ab3302SCarolineConcatto return result; 360*64ab3302SCarolineConcatto } else { 361*64ab3302SCarolineConcatto // Could not parse a decimal floating-point number. p has been 362*64ab3302SCarolineConcatto // advanced over any leading spaces. 363*64ab3302SCarolineConcatto if (toupper(p[0]) == 'N' && toupper(p[1]) == 'A' && toupper(p[2]) == 'N') { 364*64ab3302SCarolineConcatto // NaN 365*64ab3302SCarolineConcatto p += 3; 366*64ab3302SCarolineConcatto return {Real{NaN()}}; 367*64ab3302SCarolineConcatto } else { 368*64ab3302SCarolineConcatto // Try to parse Inf, maybe with a sign 369*64ab3302SCarolineConcatto const char *q{p}; 370*64ab3302SCarolineConcatto isNegative_ = *q == '-'; 371*64ab3302SCarolineConcatto if (*q == '-' || *q == '+') { 372*64ab3302SCarolineConcatto ++q; 373*64ab3302SCarolineConcatto } 374*64ab3302SCarolineConcatto if (toupper(q[0]) == 'I' && toupper(q[1]) == 'N' && 375*64ab3302SCarolineConcatto toupper(q[2]) == 'F') { 376*64ab3302SCarolineConcatto p = q + 3; 377*64ab3302SCarolineConcatto return {Real{Infinity()}}; 378*64ab3302SCarolineConcatto } else { 379*64ab3302SCarolineConcatto // Invalid input 380*64ab3302SCarolineConcatto return {Real{NaN()}, Invalid}; 381*64ab3302SCarolineConcatto } 382*64ab3302SCarolineConcatto } 383*64ab3302SCarolineConcatto } 384*64ab3302SCarolineConcatto } 385*64ab3302SCarolineConcatto 386*64ab3302SCarolineConcatto template<int PREC> 387*64ab3302SCarolineConcatto ConversionToBinaryResult<PREC> ConvertToBinary( 388*64ab3302SCarolineConcatto const char *&p, enum FortranRounding rounding) { 389*64ab3302SCarolineConcatto return BigRadixFloatingPointNumber<PREC>{rounding}.ConvertToBinary(p); 390*64ab3302SCarolineConcatto } 391*64ab3302SCarolineConcatto 392*64ab3302SCarolineConcatto template ConversionToBinaryResult<8> ConvertToBinary<8>( 393*64ab3302SCarolineConcatto const char *&, enum FortranRounding); 394*64ab3302SCarolineConcatto template ConversionToBinaryResult<11> ConvertToBinary<11>( 395*64ab3302SCarolineConcatto const char *&, enum FortranRounding); 396*64ab3302SCarolineConcatto template ConversionToBinaryResult<24> ConvertToBinary<24>( 397*64ab3302SCarolineConcatto const char *&, enum FortranRounding); 398*64ab3302SCarolineConcatto template ConversionToBinaryResult<53> ConvertToBinary<53>( 399*64ab3302SCarolineConcatto const char *&, enum FortranRounding); 400*64ab3302SCarolineConcatto template ConversionToBinaryResult<64> ConvertToBinary<64>( 401*64ab3302SCarolineConcatto const char *&, enum FortranRounding); 402*64ab3302SCarolineConcatto template ConversionToBinaryResult<112> ConvertToBinary<112>( 403*64ab3302SCarolineConcatto const char *&, enum FortranRounding); 404*64ab3302SCarolineConcatto 405*64ab3302SCarolineConcatto extern "C" { 406*64ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToFloat( 407*64ab3302SCarolineConcatto const char **p, float *f, enum FortranRounding rounding) { 408*64ab3302SCarolineConcatto auto result{Fortran::decimal::ConvertToBinary<24>(*p, rounding)}; 409*64ab3302SCarolineConcatto std::memcpy(reinterpret_cast<void *>(f), 410*64ab3302SCarolineConcatto reinterpret_cast<const void *>(&result.binary), sizeof *f); 411*64ab3302SCarolineConcatto return result.flags; 412*64ab3302SCarolineConcatto } 413*64ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToDouble( 414*64ab3302SCarolineConcatto const char **p, double *d, enum FortranRounding rounding) { 415*64ab3302SCarolineConcatto auto result{Fortran::decimal::ConvertToBinary<53>(*p, rounding)}; 416*64ab3302SCarolineConcatto std::memcpy(reinterpret_cast<void *>(d), 417*64ab3302SCarolineConcatto reinterpret_cast<const void *>(&result.binary), sizeof *d); 418*64ab3302SCarolineConcatto return result.flags; 419*64ab3302SCarolineConcatto } 420*64ab3302SCarolineConcatto #if __x86_64__ && !defined(_MSC_VER) 421*64ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToLongDouble( 422*64ab3302SCarolineConcatto const char **p, long double *ld, enum FortranRounding rounding) { 423*64ab3302SCarolineConcatto auto result{Fortran::decimal::ConvertToBinary<64>(*p, rounding)}; 424*64ab3302SCarolineConcatto std::memcpy(reinterpret_cast<void *>(ld), 425*64ab3302SCarolineConcatto reinterpret_cast<const void *>(&result.binary), sizeof *ld); 426*64ab3302SCarolineConcatto return result.flags; 427*64ab3302SCarolineConcatto } 428*64ab3302SCarolineConcatto #endif 429*64ab3302SCarolineConcatto } 430*64ab3302SCarolineConcatto } 431