44template <
typename WORD,
int PREC>
class Real {
47 static constexpr int binaryPrecision{PREC};
49 static constexpr int exponentBias{realChars.exponentBias};
50 static constexpr int exponentBits{realChars.exponentBits};
51 static constexpr int isImplicitMSB{realChars.isImplicitMSB};
52 static constexpr int maxExponent{realChars.maxExponent};
53 static constexpr int significandBits{realChars.significandBits};
55 static constexpr int bits{Word::bits};
56 static_assert(bits >= realChars.bits);
59 template <
typename W,
int P>
friend class Real;
62 constexpr Real(
const Real &) =
default;
63 constexpr Real(Real &&) =
default;
64 constexpr Real(
const Word &bits) : word_{bits} {}
65 constexpr Real &operator=(
const Real &) =
default;
66 constexpr Real &operator=(Real &&) =
default;
68 constexpr bool operator==(
const Real &that)
const {
69 return word_ == that.word_;
72 constexpr bool IsSignBitSet()
const {
return word_.BTEST(bits - 1); }
73 constexpr bool IsNegative()
const {
74 return !IsNotANumber() && IsSignBitSet();
76 constexpr bool IsNotANumber()
const {
77 auto expo{Exponent()};
78 auto sig{GetSignificand()};
79 if constexpr (bits == 80) {
81 if (expo == maxExponent) {
82 return sig != Significand{}.IBSET(63);
84 return expo != 0 && !sig.BTEST(63);
87 return expo == maxExponent && !sig.IsZero();
90 constexpr bool IsQuietNaN()
const {
91 auto expo{Exponent()};
92 auto sig{GetSignificand()};
93 if constexpr (bits == 80) {
94 if (expo == maxExponent) {
95 return sig.IBITS(62, 2) == 3;
97 return expo != 0 && !sig.BTEST(63);
100 return expo == maxExponent && sig.BTEST(significandBits - 1);
103 constexpr bool IsSignalingNaN()
const {
104 auto expo{Exponent()};
105 auto sig{GetSignificand()};
106 if constexpr (bits == 80) {
107 return expo == maxExponent && sig != Significand{}.IBSET(63) &&
108 sig.IBITS(62, 2) != 3;
110 return expo == maxExponent && !sig.IsZero() &&
111 !sig.BTEST(significandBits - 1);
114 constexpr bool IsInfinite()
const {
115 if constexpr (bits == 80) {
117 return Exponent() == maxExponent &&
118 GetSignificand() == Significand{}.IBSET(63);
120 return Exponent() == maxExponent && GetSignificand().IsZero();
123 constexpr bool IsFinite()
const {
124 auto expo{Exponent()};
125 if constexpr (bits == 80) {
126 return expo != maxExponent && (expo == 0 || GetSignificand().BTEST(63));
128 return expo != maxExponent;
131 constexpr bool IsZero()
const {
132 return Exponent() == 0 && GetSignificand().IsZero();
134 constexpr bool IsSubnormal()
const {
135 return Exponent() == 0 && !GetSignificand().IsZero();
137 constexpr bool IsNormal()
const {
138 return !(IsInfinite() || IsNotANumber() || IsSubnormal());
141 constexpr Real ABS()
const {
142 return {word_.IBCLR(bits - 1)};
144 constexpr Real SetSign(
bool toNegative)
const {
146 return {word_.IBSET(bits - 1)};
151 constexpr Real SIGN(
const Real &x)
const {
return SetSign(x.IsSignBitSet()); }
153 constexpr Real Negate()
const {
return {word_.IEOR(word_.MASKL(1))}; }
155 Relation Compare(
const Real &)
const;
157 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
159 Rounding rounding = TargetCharacteristics::defaultRounding)
const {
160 return Add(y.Negate(), rounding);
163 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
165 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
168 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
174 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
177 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
181 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
183 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
185 Rounding rounding = TargetCharacteristics::defaultRounding)
const;
187 template <
typename INT>
constexpr INT EXPONENT()
const {
188 if (Exponent() == maxExponent) {
190 }
else if (IsZero()) {
193 return {UnbiasedExponent() + 1};
197 static constexpr Real EPSILON() {
200 false, exponentBias + 1 - binaryPrecision, Fraction::MASKL(1));
203 static constexpr Real HUGE() {
205 huge.Normalize(
false, maxExponent - 1, Fraction::MASKR(binaryPrecision));
208 static constexpr Real TINY() {
210 tiny.Normalize(
false, 1, Fraction::MASKL(1));
214 static constexpr int DIGITS{binaryPrecision};
215 static constexpr int PRECISION{realChars.decimalPrecision};
216 static constexpr int RANGE{realChars.decimalRange};
217 static constexpr int MAXEXPONENT{maxExponent - exponentBias};
218 static constexpr int MINEXPONENT{2 - exponentBias};
219 Real RRSPACING()
const;
220 Real SPACING()
const;
221 Real SET_EXPONENT(std::int64_t)
const;
222 Real FRACTION()
const;
225 template <
typename INT>
227 Rounding rounding = TargetCharacteristics::defaultRounding)
const {
231 constexpr auto adjust{exponentBias + binaryPrecision - 1};
232 constexpr auto maxCoeffExpo{maxExponent + binaryPrecision - 1};
233 auto expo{adjust + by.ToInt64()};
238 }
else if (expo > maxCoeffExpo) {
239 if (Exponent() < exponentBias) {
241 return SCALE(INT{exponentBias})
242 .value.SCALE(by.SubtractSigned(INT{exponentBias}).value, rounding);
246 }
else if (expo < 0) {
247 if (Exponent() > exponentBias) {
249 return SCALE(INT{-exponentBias})
250 .value.SCALE(by.AddSigned(INT{exponentBias}).value, rounding);
254 flags.set(RealFlag::Underflow);
259 twoPow.Normalize(
false,
static_cast<int>(expo), Fraction::MASKR(rMask));
261 result.flags |= flags;
265 constexpr Real FlushSubnormalToZero()
const {
273 static constexpr Real NotANumber() {
274 return {Word{maxExponent}
275 .SHIFTL(significandBits)
276 .IBSET(significandBits - 1)
277 .IBSET(significandBits - 2)};
280 static constexpr Real PositiveZero() {
return Real{}; }
282 static constexpr Real NegativeZero() {
return {Word{}.MASKL(1)}; }
284 static constexpr Real Infinity(
bool negative) {
285 Word infinity{maxExponent};
286 infinity = infinity.SHIFTL(significandBits);
288 infinity = infinity.IBSET(infinity.bits - 1);
290 if constexpr (bits == 80) {
292 infinity = infinity.IBSET(63);
297 template <
typename INT>
299 bool isUnsigned =
false,
300 Rounding rounding = TargetCharacteristics::defaultRounding) {
301 bool isNegative{!isUnsigned && n.IsNegative()};
304 absN = n.Negate().value;
306 int leadz{absN.LEADZ()};
307 if (leadz >= absN.bits) {
311 int exponent{exponentBias + absN.bits - leadz - 1};
312 int bitsNeeded{absN.bits - (leadz + isImplicitMSB)};
313 int bitsLost{bitsNeeded - significandBits};
315 Fraction fraction{Fraction::ConvertUnsigned(absN).value};
316 result.flags |= result.value.Normalize(
317 isNegative, exponent, fraction.SHIFTL(-bitsLost));
319 Fraction fraction{Fraction::ConvertUnsigned(absN.SHIFTR(bitsLost)).value};
320 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
322 result.flags |= result.value.Round(rounding, roundingBits);
329 common::RoundingMode = common::RoundingMode::ToZero)
const;
332 template <
typename INT>
334 common::RoundingMode mode = common::RoundingMode::ToZero)
const {
336 if (IsNotANumber()) {
337 result.flags.set(RealFlag::InvalidArgument);
338 result.value = result.value.HUGE();
342 result.flags |= intPart.flags;
343 int exponent{intPart.value.Exponent()};
345 int shift{exponent - exponentBias - binaryPrecision + 1};
347 auto rshifted{intPart.value.GetFraction().SHIFTR(-shift)};
348 auto converted{result.value.ConvertUnsigned(rshifted)};
349 if (converted.overflow) {
350 result.flags.set(RealFlag::Overflow);
352 result.value = converted.value.SHIFTL(shift);
353 if (converted.value.CompareUnsigned(result.value.SHIFTR(shift)) !=
355 result.flags.set(RealFlag::Overflow);
357 if (IsSignBitSet()) {
358 result.value = result.value.Negate().value;
360 if (!result.value.IsZero()) {
361 if (IsSignBitSet() != result.value.IsNegative()) {
362 result.flags.set(RealFlag::Overflow);
365 if (result.flags.test(RealFlag::Overflow)) {
367 IsSignBitSet() ? result.value.MASKL(1) : result.value.HUGE();
372 template <
typename A>
374 const A &x,
Rounding rounding = TargetCharacteristics::defaultRounding) {
376 if (x.IsNotANumber()) {
377 result.flags.set(RealFlag::InvalidArgument);
378 result.value = NotANumber();
381 bool isNegative{x.IsNegative()};
382 if (x.IsInfinite()) {
383 result.value = Infinity(isNegative);
390 int exponent{exponentBias + x.UnbiasedExponent()};
391 int bitsLost{A::binaryPrecision - binaryPrecision};
393 bitsLost += 1 - exponent;
396 typename A::Fraction xFraction{x.GetFraction()};
399 Fraction::ConvertUnsigned(xFraction).value.SHIFTL(-bitsLost)};
400 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
403 Fraction::ConvertUnsigned(xFraction.SHIFTR(bitsLost)).value};
404 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
406 result.flags |= result.value.Round(rounding, roundingBits);
411 constexpr Word RawBits()
const {
return word_; }
414 constexpr int Exponent()
const {
415 return word_.IBITS(significandBits, exponentBits).ToUInt64();
419 constexpr Fraction GetFraction()
const {
420 Fraction result{Fraction::ConvertUnsigned(word_).value};
421 if constexpr (!isImplicitMSB) {
424 int exponent{Exponent()};
425 if (exponent > 0 && exponent < maxExponent) {
426 return result.IBSET(significandBits);
428 return result.IBCLR(significandBits);
437 constexpr int UnbiasedExponent()
const {
438 int exponent{Exponent() - exponentBias};
446 Rounding rounding = TargetCharacteristics::defaultRounding);
447 std::string DumpHexadecimal()
const;
451 llvm::raw_ostream &AsFortran(
452 llvm::raw_ostream &,
int kind,
bool minimal =
false)
const;
453 std::string AsFortran(
int kind,
bool minimal =
false)
const;
458 constexpr Significand GetSignificand()
const {
459 return Significand::ConvertUnsigned(word_).value;
462 constexpr int CombineExponents(
const Real &y,
bool forDivide)
const {
463 int exponent = Exponent(), yExponent = y.Exponent();
465 exponent += !exponent;
466 yExponent += !yExponent;
468 exponent += exponentBias - yExponent;
470 exponent += yExponent - exponentBias + 1;
475 static constexpr bool NextQuotientBit(
476 Fraction &top,
bool &msb,
const Fraction &divisor) {
477 bool greaterOrEqual{msb || top.CompareUnsigned(divisor) != Ordering::Less};
478 if (greaterOrEqual) {
479 top = top.SubtractSigned(divisor).value;
481 auto doubled{top.AddUnsigned(top)};
484 return greaterOrEqual;
491 RealFlags Normalize(
bool negative,
int exponent,
const Fraction &fraction,
492 Rounding rounding = TargetCharacteristics::defaultRounding,
500 bool multiply =
false);
505 alignas(Word::alignment / 8) Word word_{};