38template <
typename WORD,
int PREC>
class Real {
41 static constexpr int binaryPrecision{PREC};
43 static constexpr int exponentBias{realChars.exponentBias};
44 static constexpr int exponentBits{realChars.exponentBits};
45 static constexpr int isImplicitMSB{realChars.isImplicitMSB};
46 static constexpr int maxExponent{realChars.maxExponent};
47 static constexpr int significandBits{realChars.significandBits};
49 static constexpr int bits{Word::bits};
50 static_assert(bits >= realChars.bits);
53 template <
typename W,
int P>
friend class Real;
56 constexpr Real(
const Real &) =
default;
57 constexpr Real(Real &&) =
default;
58 constexpr Real(
const Word &bits) : word_{bits} {}
59 constexpr Real &operator=(
const Real &) =
default;
60 constexpr Real &operator=(Real &&) =
default;
62 constexpr bool operator==(
const Real &that)
const {
63 return word_ == that.word_;
66 constexpr bool IsSignBitSet()
const {
return word_.BTEST(bits - 1); }
67 constexpr bool IsNegative()
const {
68 return !IsNotANumber() && IsSignBitSet();
70 constexpr bool IsNotANumber()
const {
71 auto expo{Exponent()};
72 auto sig{GetSignificand()};
73 if constexpr (bits == 80) {
75 if (expo == maxExponent) {
76 return sig != Significand{}.IBSET(63);
78 return expo != 0 && !sig.BTEST(63);
81 return expo == maxExponent && !sig.IsZero();
84 constexpr bool IsQuietNaN()
const {
85 auto expo{Exponent()};
86 auto sig{GetSignificand()};
87 if constexpr (bits == 80) {
88 if (expo == maxExponent) {
89 return sig.IBITS(62, 2) == 3;
91 return expo != 0 && !sig.BTEST(63);
94 return expo == maxExponent && sig.BTEST(significandBits - 1);
97 constexpr bool IsSignalingNaN()
const {
98 auto expo{Exponent()};
99 auto sig{GetSignificand()};
100 if constexpr (bits == 80) {
101 return expo == maxExponent && sig != Significand{}.IBSET(63) &&
102 sig.IBITS(62, 2) != 3;
104 return expo == maxExponent && !sig.IsZero() &&
105 !sig.BTEST(significandBits - 1);
108 constexpr bool IsInfinite()
const {
109 if constexpr (bits == 80) {
111 return Exponent() == maxExponent &&
112 GetSignificand() == Significand{}.IBSET(63);
114 return Exponent() == maxExponent && GetSignificand().IsZero();
117 constexpr bool IsFinite()
const {
118 auto expo{Exponent()};
119 if constexpr (bits == 80) {
120 return expo != maxExponent && (expo == 0 || GetSignificand().BTEST(63));
122 return expo != maxExponent;
125 constexpr bool IsZero()
const {
126 return Exponent() == 0 && GetSignificand().IsZero();
128 constexpr bool IsSubnormal()
const {
129 return Exponent() == 0 && !GetSignificand().IsZero();
131 constexpr bool IsNormal()
const {
132 return !(IsInfinite() || IsNotANumber() || IsSubnormal());
135 constexpr Real ABS()
const {
136 return {word_.IBCLR(bits - 1)};
138 constexpr Real SetSign(
bool toNegative)
const {
140 return {word_.IBSET(bits - 1)};
145 constexpr Real SIGN(
const Real &x)
const {
return SetSign(x.IsSignBitSet()); }
147 constexpr Real Negate()
const {
return {word_.IEOR(word_.MASKL(1))}; }
149 Relation Compare(
const Real &)
const;
151 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
153 Rounding rounding = TargetCharacteristics::defaultRounding)
const {
154 return Add(y.Negate(), rounding);
157 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
159 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
162 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
168 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
171 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
175 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
177 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
179 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
181 template <
typename INT>
constexpr INT EXPONENT()
const {
182 if (Exponent() == maxExponent) {
184 }
else if (IsZero()) {
187 return {UnbiasedExponent() + 1};
191 static constexpr Real EPSILON() {
194 false, exponentBias + 1 - binaryPrecision, Fraction::MASKL(1));
197 static constexpr Real HUGE() {
199 huge.Normalize(
false, maxExponent - 1, Fraction::MASKR(binaryPrecision));
202 static constexpr Real TINY() {
204 tiny.Normalize(
false, 1, Fraction::MASKL(1));
208 static constexpr int DIGITS{binaryPrecision};
209 static constexpr int PRECISION{realChars.decimalPrecision};
210 static constexpr int RANGE{realChars.decimalRange};
211 static constexpr int MAXEXPONENT{maxExponent - exponentBias};
212 static constexpr int MINEXPONENT{2 - exponentBias};
213 Real RRSPACING()
const;
214 Real SPACING()
const;
215 Real SET_EXPONENT(std::int64_t)
const;
216 Real FRACTION()
const;
219 template <
typename INT>
221 Rounding rounding = TargetCharacteristics::defaultRounding)
const {
225 constexpr auto adjust{exponentBias + binaryPrecision - 1};
226 constexpr auto maxCoeffExpo{maxExponent + binaryPrecision - 1};
227 auto expo{adjust + by.ToInt64()};
232 }
else if (expo > maxCoeffExpo) {
233 if (Exponent() < exponentBias) {
235 return SCALE(INT{exponentBias})
236 .value.SCALE(by.SubtractSigned(INT{exponentBias}).value, rounding);
240 }
else if (expo < 0) {
241 if (Exponent() > exponentBias) {
243 return SCALE(INT{-exponentBias})
244 .value.SCALE(by.AddSigned(INT{exponentBias}).value, rounding);
248 flags.set(RealFlag::Underflow);
253 twoPow.Normalize(
false,
static_cast<int>(expo), Fraction::MASKR(rMask));
255 result.flags |= flags;
259 constexpr Real FlushSubnormalToZero()
const {
267 static constexpr Real NotANumber() {
268 return {Word{maxExponent}
269 .SHIFTL(significandBits)
270 .IBSET(significandBits - 1)
271 .IBSET(significandBits - 2)};
274 static constexpr Real PositiveZero() {
return Real{}; }
276 static constexpr Real NegativeZero() {
return {Word{}.MASKL(1)}; }
278 static constexpr Real Infinity(
bool negative) {
279 Word infinity{maxExponent};
280 infinity = infinity.SHIFTL(significandBits);
282 infinity = infinity.IBSET(infinity.bits - 1);
284 if constexpr (bits == 80) {
286 infinity = infinity.IBSET(63);
291 template <
typename INT>
293 bool isUnsigned =
false,
294 Rounding rounding = TargetCharacteristics::defaultRounding) {
295 bool isNegative{!isUnsigned && n.IsNegative()};
298 absN = n.Negate().value;
300 int leadz{absN.LEADZ()};
301 if (leadz >= absN.bits) {
305 int exponent{exponentBias + absN.bits - leadz - 1};
306 int bitsNeeded{absN.bits - (leadz + isImplicitMSB)};
307 int bitsLost{bitsNeeded - significandBits};
309 Fraction fraction{Fraction::ConvertUnsigned(absN).value};
310 result.flags |= result.value.Normalize(
311 isNegative, exponent, fraction.SHIFTL(-bitsLost));
313 Fraction fraction{Fraction::ConvertUnsigned(absN.SHIFTR(bitsLost)).value};
314 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
316 result.flags |= result.value.Round(rounding, roundingBits);
323 common::RoundingMode = common::RoundingMode::ToZero)
const;
326 template <
typename INT>
328 common::RoundingMode mode = common::RoundingMode::ToZero)
const {
330 if (IsNotANumber()) {
331 result.flags.set(RealFlag::InvalidArgument);
332 result.value = result.value.HUGE();
336 result.flags |= intPart.flags;
337 int exponent{intPart.value.Exponent()};
339 int shift{exponent - exponentBias - binaryPrecision + 1};
341 auto rshifted{intPart.value.GetFraction().SHIFTR(-shift)};
342 auto converted{result.value.ConvertUnsigned(rshifted)};
343 if (converted.overflow) {
344 result.flags.set(RealFlag::Overflow);
346 result.value = converted.value.SHIFTL(shift);
347 if (converted.value.CompareUnsigned(result.value.SHIFTR(shift)) !=
349 result.flags.set(RealFlag::Overflow);
351 if (IsSignBitSet()) {
352 result.value = result.value.Negate().value;
354 if (!result.value.IsZero()) {
355 if (IsSignBitSet() != result.value.IsNegative()) {
356 result.flags.set(RealFlag::Overflow);
359 if (result.flags.test(RealFlag::Overflow)) {
361 IsSignBitSet() ? result.value.MASKL(1) : result.value.HUGE();
366 template <
typename A>
368 const A &x,
Rounding rounding = TargetCharacteristics::defaultRounding) {
370 if (x.IsNotANumber()) {
371 result.flags.set(RealFlag::InvalidArgument);
372 result.value = NotANumber();
375 bool isNegative{x.IsNegative()};
376 if (x.IsInfinite()) {
377 result.value = Infinity(isNegative);
384 int exponent{exponentBias + x.UnbiasedExponent()};
385 int bitsLost{A::binaryPrecision - binaryPrecision};
387 bitsLost += 1 - exponent;
390 typename A::Fraction xFraction{x.GetFraction()};
393 Fraction::ConvertUnsigned(xFraction).value.SHIFTL(-bitsLost)};
394 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
397 Fraction::ConvertUnsigned(xFraction.SHIFTR(bitsLost)).value};
398 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
400 result.flags |= result.value.Round(rounding, roundingBits);
405 constexpr Word RawBits()
const {
return word_; }
408 constexpr int Exponent()
const {
409 return word_.IBITS(significandBits, exponentBits).ToUInt64();
413 constexpr Fraction GetFraction()
const {
414 Fraction result{Fraction::ConvertUnsigned(word_).value};
415 if constexpr (!isImplicitMSB) {
418 int exponent{Exponent()};
419 if (exponent > 0 && exponent < maxExponent) {
420 return result.IBSET(significandBits);
422 return result.IBCLR(significandBits);
431 constexpr int UnbiasedExponent()
const {
432 int exponent{Exponent() - exponentBias};
440 Rounding rounding = TargetCharacteristics::defaultRounding);
441 std::string DumpHexadecimal()
const;
445 llvm::raw_ostream &AsFortran(
446 llvm::raw_ostream &,
int kind,
bool minimal =
false)
const;
447 std::string AsFortran(
int kind,
bool minimal =
false)
const;
457 const void *raw, [[maybe_unused]] std::size_t expectedSize) {
465 bool *changed =
nullptr)
const {
466 word_.StoreRawBytes(dst, expectedSize, changed);
472 constexpr Significand GetSignificand()
const {
473 return Significand::ConvertUnsigned(word_).value;
476 constexpr int CombineExponents(
const Real &y,
bool forDivide)
const {
477 int exponent = Exponent(), yExponent = y.Exponent();
479 exponent += !exponent;
480 yExponent += !yExponent;
482 exponent += exponentBias - yExponent;
484 exponent += yExponent - exponentBias + 1;
489 static constexpr bool NextQuotientBit(
490 Fraction &top,
bool &msb,
const Fraction &divisor) {
491 bool greaterOrEqual{msb || top.CompareUnsigned(divisor) != Ordering::Less};
492 if (greaterOrEqual) {
493 top = top.SubtractSigned(divisor).value;
495 auto doubled{top.AddUnsigned(top)};
498 return greaterOrEqual;
505 RealFlags Normalize(
bool negative,
int exponent,
const Fraction &fraction,
506 Rounding rounding = TargetCharacteristics::defaultRounding,
507 RoundingBits *roundingBits =
nullptr);
510 RealFlags Round(Rounding,
const RoundingBits &,
bool multiply =
false);
512 static void NormalizeAndRound(ValueWithRealFlags<Real> &result,
513 bool isNegative,
int exponent,
const Fraction &, Rounding, RoundingBits,
514 bool multiply =
false);
524#pragma clang diagnostic push
525#pragma clang diagnostic ignored "-Wunknown-warning-option"
526#pragma clang diagnostic ignored "-Waix-compat"
528 alignas(Word::alignment / 8) Word word_{};
530#pragma clang diagnostic pop