9#ifndef FORTRAN_DECIMAL_BIG_RADIX_FLOATING_POINT_H_
10#define FORTRAN_DECIMAL_BIG_RADIX_FLOATING_POINT_H_
24#include "flang/Common/bit-population-count.h"
25#include "flang/Common/leading-zero-bit-count.h"
26#include "flang/Common/uint128.h"
27#include "flang/Decimal/binary-floating-point.h"
28#include "flang/Decimal/decimal.h"
37namespace Fortran::decimal {
39static constexpr std::uint64_t TenToThe(
int power) {
40 return power <= 0 ? 1 : 10 * TenToThe(power - 1);
49 static constexpr int log10Radix{LOG10RADIX};
52 static constexpr std::uint64_t uint64Radix{TenToThe(log10Radix)};
53 static constexpr int minDigitBits{
54 64 - common::LeadingZeroBitCount(uint64Radix)};
55 using Digit = common::HostUnsignedIntType<minDigitBits>;
56 static constexpr Digit radix{uint64Radix};
57 static_assert(radix < std::numeric_limits<Digit>::max() / 1000,
58 "radix is somehow too big");
59 static_assert(radix > std::numeric_limits<Digit>::max() / 10000,
60 "radix is somehow too small");
64 static constexpr int minLog2AnyBit{
65 -Real::exponentBias - Real::binaryPrecision};
68 static constexpr int maxDigits{3 - minLog2AnyBit / log10Radix};
72 enum FortranRounding rounding = RoundNearest)
73 : rounding_{rounding} {}
77 Real,
enum FortranRounding = RoundNearest);
86 RT_API_ATTRS
bool IsInteger()
const {
return exponent_ >= 0; }
89 RT_API_ATTRS ConversionToBinaryResult<PREC> ConvertToBinary();
96 RT_API_ATTRS ConversionToBinaryResult<PREC> ConvertToBinary(
97 const char *&,
const char *end =
nullptr);
106 char *, std::size_t,
enum DecimalConversionFlags,
int digits)
const;
117 RT_API_ATTRS
void Minimize(
120 template <
typename STREAM> STREAM &Dump(STREAM &)
const;
125 : digits_{that.digits_}, exponent_{that.exponent_},
126 isNegative_{that.isNegative_}, rounding_{that.rounding_} {
127 for (
int j{0}; j < digits_; ++j) {
128 digit_[j] = that.digit_[j];
132 RT_API_ATTRS
bool IsZero()
const {
134 for (
int j{0}; j < digits_; ++j) {
135 if (digit_[j] != 0) {
146 RT_API_ATTRS
bool IsFull()
const {
147 return digits_ == digitLimit_ && digit_[digits_ - 1] >= radix / 10;
152 template <
typename UINT> RT_API_ATTRS UINT SetTo(UINT n) {
154 std::is_same_v<UINT, common::uint128_t> || std::is_unsigned_v<UINT>);
164 if constexpr (
sizeof n <
sizeof(Digit)) {
166 digit_[digits_++] = n;
170 while (n != 0 && digits_ < digitLimit_) {
172 digit_[digits_++] =
static_cast<Digit
>(n - q * radix);
179 RT_API_ATTRS
int RemoveLeastOrderZeroDigits() {
181 if (digits_ > 0 && digit_[0] == 0) {
182 while (remove < digits_ && digit_[remove] == 0) {
185 if (remove >= digits_) {
187 }
else if (remove > 0) {
188#if defined __GNUC__ && __GNUC__ < 8
191 for (
int j{0}; j + remove < digits_ && (j + remove < maxDigits); ++j) {
193 for (
int j{0}; j + remove < digits_; ++j) {
195 digit_[j] = digit_[j + remove];
203 RT_API_ATTRS
void RemoveLeadingZeroDigits() {
204 while (digits_ > 0 && digit_[digits_ - 1] == 0) {
209 RT_API_ATTRS
void Normalize() {
210 RemoveLeadingZeroDigits();
211 exponent_ += RemoveLeastOrderZeroDigits() * log10Radix;
216 template <
int N> RT_API_ATTRS
bool IsDivisibleBy()
const {
217 static_assert(N > 1 && radix % N == 0,
"bad modulus");
218 return digits_ == 0 || (digit_[0] % N) == 0;
221 template <
unsigned DIVISOR> RT_API_ATTRS
int DivideBy() {
223 for (
int j{digits_ - 1}; j >= 0; --j) {
224 Digit q{digit_[j] / DIVISOR};
225 Digit nrem{digit_[j] - DIVISOR * q};
226 digit_[j] = q + (radix / DIVISOR) * remainder;
232 RT_API_ATTRS
void DivideByPowerOfTwo(
int twoPow) {
234 auto mask{(Digit{1} << twoPow) - 1};
235 auto coeff{radix >> twoPow};
236 for (
int j{digits_ - 1}; j >= 0; --j) {
237 auto nrem{digit_[j] & mask};
238 digit_[j] = (digit_[j] >> twoPow) + coeff * remainder;
244 RT_API_ATTRS
bool DivideByPowerOfTwoInPlace(
int twoPow) {
247 int chunk{twoPow > log10Radix ? log10Radix : twoPow};
248 if ((digit_[0] & ((Digit{1} << chunk) - 1)) == 0) {
249 DivideByPowerOfTwo(chunk);
254 if (digit_[digits_ - 1] >> chunk != 0) {
255 if (digits_ == digitLimit_) {
258 digit_[digits_++] = 0;
260 auto remainder{digit_[digits_ - 1]};
261 exponent_ -= log10Radix;
262 auto coeff{radix >> chunk};
263 auto mask{(Digit{1} << chunk) - 1};
264 for (
int j{digits_ - 1}; j >= 1; --j) {
265 digit_[j] = (digit_[j - 1] >> chunk) + coeff * remainder;
266 remainder = digit_[j - 1] & mask;
268 digit_[0] = coeff * remainder;
274 RT_API_ATTRS
int AddCarry(
int position = 0,
int carry = 1) {
275 for (; position < digits_; ++position) {
276 Digit v{digit_[position] + carry};
278 digit_[position] = v;
281 digit_[position] = v - radix;
284 if (digits_ < digitLimit_) {
285 digit_[digits_++] = carry;
289 if (digits_ < digitLimit_) {
290 digit_[digits_++] = carry;
296 RT_API_ATTRS
void Decrement() {
297 for (
int j{0}; digit_[j]-- == 0; ++j) {
298 digit_[j] = radix - 1;
302 template <
int N> RT_API_ATTRS
int MultiplyByHelper(
int carry = 0) {
303 for (
int j{0}; j < digits_; ++j) {
304 auto v{N * digit_[j] + carry};
306 digit_[j] = v - carry * radix;
311 template <
int N> RT_API_ATTRS
int MultiplyBy(
int carry = 0) {
312 if (
int newCarry{MultiplyByHelper<N>(carry)}) {
313 return AddCarry(digits_, newCarry);
319 template <
int N> RT_API_ATTRS
int MultiplyWithoutNormalization() {
320 if (
int carry{MultiplyByHelper<N>(0)}) {
321 if (digits_ < digitLimit_) {
322 digit_[digits_++] = carry;
332 RT_API_ATTRS
void LoseLeastSignificantDigit();
334 RT_API_ATTRS
void PushCarry(
int carry) {
335 if (digits_ == maxDigits && RemoveLeastOrderZeroDigits() == 0) {
336 LoseLeastSignificantDigit();
337 digit_[digits_ - 1] += carry;
339 digit_[digits_++] = carry;
353 RT_API_ATTRS
bool ParseNumber(
const char *&,
bool &inexact,
const char *end);
355 using Raw =
typename Real::RawType;
356 constexpr RT_API_ATTRS Raw SignBit()
const {
357 return Raw{isNegative_} << (Real::bits - 1);
359 constexpr RT_API_ATTRS Raw Infinity()
const {
360 Raw result{
static_cast<Raw
>(Real::maxExponent)};
361 result <<= Real::significandBits;
363 if constexpr (Real::bits == 80) {
364 result |= Raw{1} << 63;
368 constexpr RT_API_ATTRS Raw NaN(
bool isQuiet =
true) {
369 Raw result{Real::maxExponent};
370 result <<= Real::significandBits;
372 if constexpr (Real::bits == 80) {
373 result |= Raw{isQuiet ? 3u : 2u} << 62;
375 Raw quiet{isQuiet ? Raw{2} : Raw{1}};
376 quiet <<= Real::significandBits - 2;
381 constexpr RT_API_ATTRS Raw HUGE()
const {
382 Raw result{
static_cast<Raw
>(Real::maxExponent)};
383 result <<= Real::significandBits;
388 Digit digit_[maxDigits];
390 int digitLimit_{maxDigits};
392 bool isNegative_{
false};
393 enum FortranRounding rounding_ { RoundNearest };
Definition: big-radix-floating-point.h:46
Definition: binary-floating-point.h:33