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 < std::numeric_limits<Digit>::max() / 1000,
57 "radix is somehow too big");
58 static_assert(radix > std::numeric_limits<Digit>::max() / 10000,
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) {
153 std::is_same_v<UINT, common::uint128_t> || std::is_unsigned_v<UINT>);
163 if constexpr (
sizeof n <
sizeof(Digit)) {
165 digit_[digits_++] = n;
169 while (n != 0 && digits_ < digitLimit_) {
171 digit_[digits_++] =
static_cast<Digit
>(n - q * radix);
178 RT_API_ATTRS
int RemoveLeastOrderZeroDigits() {
180 if (digits_ > 0 && digit_[0] == 0) {
181 while (remove < digits_ && digit_[remove] == 0) {
184 if (remove >= digits_) {
186 }
else if (remove > 0) {
187#if defined __GNUC__ && __GNUC__ < 8
190 for (
int j{0}; j + remove < digits_ && (j + remove < maxDigits); ++j) {
192 for (
int j{0}; j + remove < digits_; ++j) {
194 digit_[j] = digit_[j + remove];
202 RT_API_ATTRS
void RemoveLeadingZeroDigits() {
203 while (digits_ > 0 && digit_[digits_ - 1] == 0) {
208 RT_API_ATTRS
void Normalize() {
209 RemoveLeadingZeroDigits();
210 exponent_ += RemoveLeastOrderZeroDigits() * log10Radix;
215 template <
int N> RT_API_ATTRS
bool IsDivisibleBy()
const {
216 static_assert(N > 1 && radix % N == 0,
"bad modulus");
217 return digits_ == 0 || (digit_[0] % N) == 0;
220 template <
unsigned DIVISOR> RT_API_ATTRS
int DivideBy() {
222 for (
int j{digits_ - 1}; j >= 0; --j) {
223 Digit q{digit_[j] / DIVISOR};
224 Digit nrem{digit_[j] - DIVISOR * q};
225 digit_[j] = q + (radix / DIVISOR) * remainder;
231 RT_API_ATTRS
void DivideByPowerOfTwo(
int twoPow) {
233 auto mask{(Digit{1} << twoPow) - 1};
234 auto coeff{radix >> twoPow};
235 for (
int j{digits_ - 1}; j >= 0; --j) {
236 auto nrem{digit_[j] & mask};
237 digit_[j] = (digit_[j] >> twoPow) + coeff * remainder;
243 RT_API_ATTRS
bool DivideByPowerOfTwoInPlace(
int twoPow) {
246 int chunk{twoPow > log10Radix ? log10Radix : twoPow};
247 if ((digit_[0] & ((Digit{1} << chunk) - 1)) == 0) {
248 DivideByPowerOfTwo(chunk);
253 if (digit_[digits_ - 1] >> chunk != 0) {
254 if (digits_ == digitLimit_) {
257 digit_[digits_++] = 0;
259 auto remainder{digit_[digits_ - 1]};
260 exponent_ -= log10Radix;
261 auto coeff{radix >> chunk};
262 auto mask{(Digit{1} << chunk) - 1};
263 for (
int j{digits_ - 1}; j >= 1; --j) {
264 digit_[j] = (digit_[j - 1] >> chunk) + coeff * remainder;
265 remainder = digit_[j - 1] & mask;
267 digit_[0] = coeff * remainder;
273 RT_API_ATTRS
int AddCarry(
int position = 0,
int carry = 1) {
274 for (; position < digits_; ++position) {
275 Digit v{digit_[position] + carry};
277 digit_[position] = v;
280 digit_[position] = v - radix;
283 if (digits_ < digitLimit_) {
284 digit_[digits_++] = carry;
288 if (digits_ < digitLimit_) {
289 digit_[digits_++] = carry;
295 RT_API_ATTRS
void Decrement() {
296 for (
int j{0}; digit_[j]-- == 0; ++j) {
297 digit_[j] = radix - 1;
301 template <
int N> RT_API_ATTRS
int MultiplyByHelper(
int carry = 0) {
302 for (
int j{0}; j < digits_; ++j) {
303 auto v{N * digit_[j] + carry};
305 digit_[j] = v - carry * radix;
310 template <
int N> RT_API_ATTRS
int MultiplyBy(
int carry = 0) {
311 if (
int newCarry{MultiplyByHelper<N>(carry)}) {
312 return AddCarry(digits_, newCarry);
318 template <
int N> RT_API_ATTRS
int MultiplyWithoutNormalization() {
319 if (
int carry{MultiplyByHelper<N>(0)}) {
320 if (digits_ < digitLimit_) {
321 digit_[digits_++] = carry;
331 RT_API_ATTRS
void LoseLeastSignificantDigit();
333 RT_API_ATTRS
void PushCarry(
int carry) {
334 if (digits_ == maxDigits && RemoveLeastOrderZeroDigits() == 0) {
335 LoseLeastSignificantDigit();
336 digit_[digits_ - 1] += carry;
338 digit_[digits_++] = carry;
345 RT_API_ATTRS
bool Mean(
const BigRadixFloatingPointNumber &);
352 RT_API_ATTRS
bool ParseNumber(
const char *&,
bool &inexact,
const char *end);
354 using Raw =
typename Real::RawType;
355 constexpr RT_API_ATTRS Raw SignBit()
const {
356 return Raw{isNegative_} << (Real::bits - 1);
358 constexpr RT_API_ATTRS Raw Infinity()
const {
359 Raw result{
static_cast<Raw
>(Real::maxExponent)};
360 result <<= Real::significandBits;
362 if constexpr (Real::bits == 80) {
363 result |= Raw{1} << 63;
367 constexpr RT_API_ATTRS Raw NaN(
bool isQuiet =
true) {
368 Raw result{Real::maxExponent};
369 result <<= Real::significandBits;
371 if constexpr (Real::bits == 80) {
372 result |= Raw{isQuiet ? 3u : 2u} << 62;
374 Raw quiet{isQuiet ? Raw{2} : Raw{1}};
375 quiet <<= Real::significandBits - 2;
380 constexpr RT_API_ATTRS Raw HUGE()
const {
381 Raw result{
static_cast<Raw
>(Real::maxExponent)};
382 result <<= Real::significandBits;
387 Digit digit_[maxDigits];
389 int digitLimit_{maxDigits};
391 bool isNegative_{
false};
392 enum FortranRounding rounding_ { RoundNearest };