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>
ParseNumber(const char * & p,bool & inexact,const char * end)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,
LoseLeastSignificantDigit()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
IntermediateFloat()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.
SetTo(UINT n)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
ShiftIn(int bit=0)22064ab3302SCarolineConcatto void ShiftIn(int bit = 0) { value_ = value_ + value_ + bit; }
IsFull() const22164ab3302SCarolineConcatto bool IsFull() const { return value_ >= topBit; }
AdjustExponent(int by)22264ab3302SCarolineConcatto void AdjustExponent(int by) { exponent_ += by; }
SetGuard(int g)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>
ToBinary(bool isNegative,FortranRounding rounding) const24164ab3302SCarolineConcatto 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>
ConvertToBinary()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>
ConvertToBinary(const char * & p,const char * limit)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.
411f1dbf8e4SPeter Klausler if ((!limit || limit >= p + 3) && toupper(p[0]) == 'N' &&
412f1dbf8e4SPeter Klausler toupper(p[1]) == 'A' && toupper(p[2]) == 'N') {
41364ab3302SCarolineConcatto // NaN
41464ab3302SCarolineConcatto p += 3;
415f1dbf8e4SPeter Klausler if ((!limit || p < limit) && *p == '(') {
416f1dbf8e4SPeter Klausler int depth{1};
417f1dbf8e4SPeter Klausler do {
418f1dbf8e4SPeter Klausler ++p;
419f1dbf8e4SPeter Klausler if (limit && p >= limit) {
420f1dbf8e4SPeter Klausler // Invalid input
421f1dbf8e4SPeter Klausler return {Real{NaN()}, Invalid};
422f1dbf8e4SPeter Klausler } else if (*p == '(') {
423f1dbf8e4SPeter Klausler ++depth;
424f1dbf8e4SPeter Klausler } else if (*p == ')') {
425f1dbf8e4SPeter Klausler --depth;
426f1dbf8e4SPeter Klausler }
427f1dbf8e4SPeter Klausler } while (depth > 0);
428f1dbf8e4SPeter Klausler ++p;
429f1dbf8e4SPeter Klausler }
43064ab3302SCarolineConcatto return {Real{NaN()}};
43164ab3302SCarolineConcatto } else {
43264ab3302SCarolineConcatto // Try to parse Inf, maybe with a sign
43364ab3302SCarolineConcatto const char *q{p};
434f1dbf8e4SPeter Klausler if (!limit || q < limit) {
43564ab3302SCarolineConcatto isNegative_ = *q == '-';
436f1dbf8e4SPeter Klausler if (isNegative_ || *q == '+') {
43764ab3302SCarolineConcatto ++q;
43864ab3302SCarolineConcatto }
439f1dbf8e4SPeter Klausler }
440f1dbf8e4SPeter Klausler if ((!limit || limit >= q + 3) && toupper(q[0]) == 'I' &&
441f1dbf8e4SPeter Klausler toupper(q[1]) == 'N' && toupper(q[2]) == 'F') {
442*b8f5cf9dSPeter Klausler if ((!limit || limit >= q + 8) && toupper(q[3]) == 'I' &&
443*b8f5cf9dSPeter Klausler toupper(q[4]) == 'N' && toupper(q[5]) == 'I' &&
444*b8f5cf9dSPeter Klausler toupper(q[6]) == 'T' && toupper(q[7]) == 'Y') {
445*b8f5cf9dSPeter Klausler p = q + 8;
446*b8f5cf9dSPeter Klausler } else {
44764ab3302SCarolineConcatto p = q + 3;
448*b8f5cf9dSPeter Klausler }
44964ab3302SCarolineConcatto return {Real{Infinity()}};
45064ab3302SCarolineConcatto } else {
45164ab3302SCarolineConcatto // Invalid input
45264ab3302SCarolineConcatto return {Real{NaN()}, Invalid};
45364ab3302SCarolineConcatto }
45464ab3302SCarolineConcatto }
45564ab3302SCarolineConcatto }
45664ab3302SCarolineConcatto }
45764ab3302SCarolineConcatto
45864ab3302SCarolineConcatto template <int PREC>
ConvertToBinary(const char * & p,enum FortranRounding rounding,const char * end)45964ab3302SCarolineConcatto ConversionToBinaryResult<PREC> ConvertToBinary(
460da25f968SPeter Klausler const char *&p, enum FortranRounding rounding, const char *end) {
461da25f968SPeter Klausler return BigRadixFloatingPointNumber<PREC>{rounding}.ConvertToBinary(p, end);
46264ab3302SCarolineConcatto }
46364ab3302SCarolineConcatto
46464ab3302SCarolineConcatto template ConversionToBinaryResult<8> ConvertToBinary<8>(
465da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end);
46664ab3302SCarolineConcatto template ConversionToBinaryResult<11> ConvertToBinary<11>(
467da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end);
46864ab3302SCarolineConcatto template ConversionToBinaryResult<24> ConvertToBinary<24>(
469da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end);
47064ab3302SCarolineConcatto template ConversionToBinaryResult<53> ConvertToBinary<53>(
471da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end);
47264ab3302SCarolineConcatto template ConversionToBinaryResult<64> ConvertToBinary<64>(
473da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end);
474b7a5b5c7Speter klausler template ConversionToBinaryResult<113> ConvertToBinary<113>(
475da25f968SPeter Klausler const char *&, enum FortranRounding, const char *end);
47664ab3302SCarolineConcatto
47764ab3302SCarolineConcatto extern "C" {
ConvertDecimalToFloat(const char ** p,float * f,enum FortranRounding rounding)47864ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToFloat(
47964ab3302SCarolineConcatto const char **p, float *f, enum FortranRounding rounding) {
48064ab3302SCarolineConcatto auto result{Fortran::decimal::ConvertToBinary<24>(*p, rounding)};
48164ab3302SCarolineConcatto std::memcpy(reinterpret_cast<void *>(f),
48264ab3302SCarolineConcatto reinterpret_cast<const void *>(&result.binary), sizeof *f);
48364ab3302SCarolineConcatto return result.flags;
48464ab3302SCarolineConcatto }
ConvertDecimalToDouble(const char ** p,double * d,enum FortranRounding rounding)48564ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToDouble(
48664ab3302SCarolineConcatto const char **p, double *d, enum FortranRounding rounding) {
48764ab3302SCarolineConcatto auto result{Fortran::decimal::ConvertToBinary<53>(*p, rounding)};
48864ab3302SCarolineConcatto std::memcpy(reinterpret_cast<void *>(d),
48964ab3302SCarolineConcatto reinterpret_cast<const void *>(&result.binary), sizeof *d);
49064ab3302SCarolineConcatto return result.flags;
49164ab3302SCarolineConcatto }
ConvertDecimalToLongDouble(const char ** p,long double * ld,enum FortranRounding rounding)49264ab3302SCarolineConcatto enum ConversionResultFlags ConvertDecimalToLongDouble(
49364ab3302SCarolineConcatto const char **p, long double *ld, enum FortranRounding rounding) {
49464ab3302SCarolineConcatto auto result{Fortran::decimal::ConvertToBinary<64>(*p, rounding)};
49564ab3302SCarolineConcatto std::memcpy(reinterpret_cast<void *>(ld),
49664ab3302SCarolineConcatto reinterpret_cast<const void *>(&result.binary), sizeof *ld);
49764ab3302SCarolineConcatto return result.flags;
49864ab3302SCarolineConcatto }
49964ab3302SCarolineConcatto }
5001f879005STim Keith } // namespace Fortran::decimal
501