45template <
int PREC,
int LOG10RADIX = 16>
class BigRadixFloatingPointNumber {
48 static constexpr int log10Radix{LOG10RADIX};
51 static constexpr std::uint64_t uint64Radix{TenToThe(log10Radix)};
52 static constexpr int minDigitBits{
53 64 - common::LeadingZeroBitCount(uint64Radix)};
54 using Digit = common::HostUnsignedIntType<minDigitBits>;
55 static constexpr Digit radix{uint64Radix};
56 static_assert(radix < common::numeric_limits<Digit>::max() / 1000,
57 "radix is somehow too big");
59 "radix is somehow too small");
63 static constexpr int minLog2AnyBit{
64 -Real::exponentBias - Real::binaryPrecision};
67 static constexpr int maxDigits{3 - minLog2AnyBit / log10Radix};
70 explicit RT_API_ATTRS BigRadixFloatingPointNumber(
71 enum FortranRounding rounding = RoundNearest)
72 : rounding_{rounding} {}
75 explicit RT_API_ATTRS BigRadixFloatingPointNumber(
76 Real,
enum FortranRounding = RoundNearest);
78 RT_API_ATTRS BigRadixFloatingPointNumber &SetToZero() {
85 RT_API_ATTRS
bool IsInteger()
const {
return exponent_ >= 0; }
88 RT_API_ATTRS ConversionToBinaryResult<PREC> ConvertToBinary();
95 RT_API_ATTRS ConversionToBinaryResult<PREC> ConvertToBinary(
96 const char *&,
const char *end =
nullptr);
105 char *, std::size_t,
enum DecimalConversionFlags,
int digits)
const;
116 RT_API_ATTRS
void Minimize(
117 BigRadixFloatingPointNumber &&less, BigRadixFloatingPointNumber &&more);
119 template <
typename STREAM> STREAM &Dump(STREAM &)
const;
122 RT_API_ATTRS BigRadixFloatingPointNumber(
123 const BigRadixFloatingPointNumber &that)
124 : digits_{that.digits_}, exponent_{that.exponent_},
125 isNegative_{that.isNegative_}, rounding_{that.rounding_} {
126 for (
int j{0}; j < digits_; ++j) {
127 digit_[j] = that.digit_[j];
131 RT_API_ATTRS
bool IsZero()
const {
133 for (
int j{0}; j < digits_; ++j) {
134 if (digit_[j] != 0) {
145 RT_API_ATTRS
bool IsFull()
const {
146 return digits_ == digitLimit_ && digit_[digits_ - 1] >= radix / 10;
151 template <
typename UINT> RT_API_ATTRS UINT SetTo(UINT n) {
152 static_assert(common::is_unsigned_v<UINT>);
162 if constexpr (
sizeof n <
sizeof(Digit)) {
164 digit_[digits_++] = n;
168 while (n != 0 && digits_ < digitLimit_) {
170 digit_[digits_++] =
static_cast<Digit
>(n - q * radix);
177 RT_API_ATTRS
int RemoveLeastOrderZeroDigits() {
179 if (digits_ > 0 && digit_[0] == 0) {
180 while (remove < digits_ && digit_[remove] == 0) {
183 if (remove >= digits_) {
185 }
else if (remove > 0) {
186#if defined __GNUC__ && __GNUC__ < 8
189 for (
int j{0}; j + remove < digits_ && (j + remove < maxDigits); ++j) {
191 for (
int j{0}; j + remove < digits_; ++j) {
193 digit_[j] = digit_[j + remove];
201 RT_API_ATTRS
void RemoveLeadingZeroDigits() {
202 while (digits_ > 0 && digit_[digits_ - 1] == 0) {
207 RT_API_ATTRS
void Normalize() {
208 RemoveLeadingZeroDigits();
209 exponent_ += RemoveLeastOrderZeroDigits() * log10Radix;
214 template <
int N> RT_API_ATTRS
bool IsDivisibleBy()
const {
215 static_assert(N > 1 && radix % N == 0,
"bad modulus");
216 return digits_ == 0 || (digit_[0] % N) == 0;
219 template <
unsigned DIVISOR> RT_API_ATTRS
int DivideBy() {
221 for (
int j{digits_ - 1}; j >= 0; --j) {
222 Digit q{digit_[j] / DIVISOR};
223 Digit nrem{digit_[j] - DIVISOR * q};
224 digit_[j] = q + (radix / DIVISOR) * remainder;
230 RT_API_ATTRS
void DivideByPowerOfTwo(
int twoPow) {
232 auto mask{(Digit{1} << twoPow) - 1};
233 auto coeff{radix >> twoPow};
234 for (
int j{digits_ - 1}; j >= 0; --j) {
235 auto nrem{digit_[j] & mask};
236 digit_[j] = (digit_[j] >> twoPow) + coeff * remainder;
242 RT_API_ATTRS
bool DivideByPowerOfTwoInPlace(
int twoPow) {
245 int chunk{twoPow > log10Radix ? log10Radix : twoPow};
246 if ((digit_[0] & ((Digit{1} << chunk) - 1)) == 0) {
247 DivideByPowerOfTwo(chunk);
252 if (digit_[digits_ - 1] >> chunk != 0) {
253 if (digits_ == digitLimit_) {
256 digit_[digits_++] = 0;
258 auto remainder{digit_[digits_ - 1]};
259 exponent_ -= log10Radix;
260 auto coeff{radix >> chunk};
261 auto mask{(Digit{1} << chunk) - 1};
262 for (
int j{digits_ - 1}; j >= 1; --j) {
263 digit_[j] = (digit_[j - 1] >> chunk) + coeff * remainder;
264 remainder = digit_[j - 1] & mask;
266 digit_[0] = coeff * remainder;
272 RT_API_ATTRS
int AddCarry(
int position = 0,
int carry = 1) {
273 for (; position < digits_; ++position) {
274 Digit v{digit_[position] + carry};
276 digit_[position] = v;
279 digit_[position] = v - radix;
282 if (digits_ < digitLimit_) {
283 digit_[digits_++] = carry;
287 if (digits_ < digitLimit_) {
288 digit_[digits_++] = carry;
294 RT_API_ATTRS
void Decrement() {
295 for (
int j{0}; digit_[j]-- == 0; ++j) {
296 digit_[j] = radix - 1;
300 template <
int N> RT_API_ATTRS
int MultiplyByHelper(
int carry = 0) {
301 for (
int j{0}; j < digits_; ++j) {
302 auto v{N * digit_[j] + carry};
304 digit_[j] = v - carry * radix;
309 template <
int N> RT_API_ATTRS
int MultiplyBy(
int carry = 0) {
310 if (
int newCarry{MultiplyByHelper<N>(carry)}) {
311 return AddCarry(digits_, newCarry);
317 template <
int N> RT_API_ATTRS
int MultiplyWithoutNormalization() {
318 if (
int carry{MultiplyByHelper<N>(0)}) {
319 if (digits_ < digitLimit_) {
320 digit_[digits_++] = carry;
330 RT_API_ATTRS
void LoseLeastSignificantDigit();
332 RT_API_ATTRS
void PushCarry(
int carry) {
333 if (digits_ == maxDigits && RemoveLeastOrderZeroDigits() == 0) {
334 LoseLeastSignificantDigit();
335 digit_[digits_ - 1] += carry;
337 digit_[digits_++] = carry;
344 RT_API_ATTRS
bool Mean(
const BigRadixFloatingPointNumber &);
351 RT_API_ATTRS
bool ParseNumber(
const char *&,
bool &inexact,
const char *end);
353 using Raw =
typename Real::RawType;
354 constexpr RT_API_ATTRS Raw SignBit()
const {
355 return Raw{isNegative_} << (Real::bits - 1);
357 constexpr RT_API_ATTRS Raw Infinity()
const {
358 Raw result{
static_cast<Raw
>(Real::maxExponent)};
359 result <<= Real::significandBits;
361 if constexpr (Real::bits == 80) {
362 result |= Raw{1} << 63;
366 constexpr RT_API_ATTRS Raw NaN(
bool isQuiet =
true) {
367 Raw result{Real::maxExponent};
368 result <<= Real::significandBits;
370 if constexpr (Real::bits == 80) {
371 result |= Raw{isQuiet ? 3u : 2u} << 62;
373 Raw quiet{isQuiet ? Raw{2} : Raw{1}};
374 quiet <<= Real::significandBits - 2;
379 constexpr RT_API_ATTRS Raw HUGE()
const {
380 Raw result{
static_cast<Raw
>(Real::maxExponent)};
381 result <<= Real::significandBits;
386 Digit digit_[maxDigits];
388 int digitLimit_{maxDigits};
390 bool isNegative_{
false};
391 enum FortranRounding rounding_ { RoundNearest };