|  | //===-- lib/Evaluate/real.cpp ---------------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "flang/Evaluate/real.h" | 
|  | #include "int-power.h" | 
|  | #include "flang/Common/idioms.h" | 
|  | #include "flang/Decimal/decimal.h" | 
|  | #include "flang/Parser/characters.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include <limits> | 
|  |  | 
|  | namespace Fortran::evaluate::value { | 
|  |  | 
|  | template <typename W, int P> Relation Real<W, P>::Compare(const Real &y) const { | 
|  | if (IsNotANumber() || y.IsNotANumber()) { // NaN vs x, x vs NaN | 
|  | return Relation::Unordered; | 
|  | } else if (IsInfinite()) { | 
|  | if (y.IsInfinite()) { | 
|  | if (IsNegative()) { // -Inf vs +/-Inf | 
|  | return y.IsNegative() ? Relation::Equal : Relation::Less; | 
|  | } else { // +Inf vs +/-Inf | 
|  | return y.IsNegative() ? Relation::Greater : Relation::Equal; | 
|  | } | 
|  | } else { // +/-Inf vs finite | 
|  | return IsNegative() ? Relation::Less : Relation::Greater; | 
|  | } | 
|  | } else if (y.IsInfinite()) { // finite vs +/-Inf | 
|  | return y.IsNegative() ? Relation::Greater : Relation::Less; | 
|  | } else { // two finite numbers | 
|  | bool isNegative{IsNegative()}; | 
|  | if (isNegative != y.IsNegative()) { | 
|  | if (word_.IOR(y.word_).IBCLR(bits - 1).IsZero()) { | 
|  | return Relation::Equal; // +/-0.0 == -/+0.0 | 
|  | } else { | 
|  | return isNegative ? Relation::Less : Relation::Greater; | 
|  | } | 
|  | } else { | 
|  | // same sign | 
|  | Ordering order{evaluate::Compare(Exponent(), y.Exponent())}; | 
|  | if (order == Ordering::Equal) { | 
|  | order = GetSignificand().CompareUnsigned(y.GetSignificand()); | 
|  | } | 
|  | if (isNegative) { | 
|  | order = Reverse(order); | 
|  | } | 
|  | return RelationFromOrdering(order); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::Add( | 
|  | const Real &y, Rounding rounding) const { | 
|  | ValueWithRealFlags<Real> result; | 
|  | if (IsNotANumber() || y.IsNotANumber()) { | 
|  | result.value = NotANumber(); // NaN + x -> NaN | 
|  | if (IsSignalingNaN() || y.IsSignalingNaN()) { | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | } | 
|  | return result; | 
|  | } | 
|  | bool isNegative{IsNegative()}; | 
|  | bool yIsNegative{y.IsNegative()}; | 
|  | if (IsInfinite()) { | 
|  | if (y.IsInfinite()) { | 
|  | if (isNegative == yIsNegative) { | 
|  | result.value = *this; // +/-Inf + +/-Inf -> +/-Inf | 
|  | } else { | 
|  | result.value = NotANumber(); // +/-Inf + -/+Inf -> NaN | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | } | 
|  | } else { | 
|  | result.value = *this; // +/-Inf + x -> +/-Inf | 
|  | } | 
|  | return result; | 
|  | } | 
|  | if (y.IsInfinite()) { | 
|  | result.value = y; // x + +/-Inf -> +/-Inf | 
|  | return result; | 
|  | } | 
|  | int exponent{Exponent()}; | 
|  | int yExponent{y.Exponent()}; | 
|  | if (exponent < yExponent) { | 
|  | // y is larger in magnitude; simplify by reversing operands | 
|  | return y.Add(*this, rounding); | 
|  | } | 
|  | if (exponent == yExponent && isNegative != yIsNegative) { | 
|  | Ordering order{GetSignificand().CompareUnsigned(y.GetSignificand())}; | 
|  | if (order == Ordering::Less) { | 
|  | // Same exponent, opposite signs, and y is larger in magnitude | 
|  | return y.Add(*this, rounding); | 
|  | } | 
|  | if (order == Ordering::Equal) { | 
|  | // x + (-x) -> +0.0 unless rounding is directed downwards | 
|  | if (rounding.mode == common::RoundingMode::Down) { | 
|  | result.value = NegativeZero(); | 
|  | } | 
|  | return result; | 
|  | } | 
|  | } | 
|  | // Our exponent is greater than y's, or the exponents match and y is not | 
|  | // of the opposite sign and greater magnitude.  So (x+y) will have the | 
|  | // same sign as x. | 
|  | Fraction fraction{GetFraction()}; | 
|  | Fraction yFraction{y.GetFraction()}; | 
|  | int rshift = exponent - yExponent; | 
|  | if (exponent > 0 && yExponent == 0) { | 
|  | --rshift; // correct overshift when only y is subnormal | 
|  | } | 
|  | RoundingBits roundingBits{yFraction, rshift}; | 
|  | yFraction = yFraction.SHIFTR(rshift); | 
|  | bool carry{false}; | 
|  | if (isNegative != yIsNegative) { | 
|  | // Opposite signs: subtract via addition of two's complement of y and | 
|  | // the rounding bits. | 
|  | yFraction = yFraction.NOT(); | 
|  | carry = roundingBits.Negate(); | 
|  | } | 
|  | auto sum{fraction.AddUnsigned(yFraction, carry)}; | 
|  | fraction = sum.value; | 
|  | if (isNegative == yIsNegative && sum.carry) { | 
|  | roundingBits.ShiftRight(sum.value.BTEST(0)); | 
|  | fraction = fraction.SHIFTR(1).IBSET(fraction.bits - 1); | 
|  | ++exponent; | 
|  | } | 
|  | NormalizeAndRound( | 
|  | result, isNegative, exponent, fraction, rounding, roundingBits); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::Multiply( | 
|  | const Real &y, Rounding rounding) const { | 
|  | ValueWithRealFlags<Real> result; | 
|  | if (IsNotANumber() || y.IsNotANumber()) { | 
|  | result.value = NotANumber(); // NaN * x -> NaN | 
|  | if (IsSignalingNaN() || y.IsSignalingNaN()) { | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | } | 
|  | } else { | 
|  | bool isNegative{IsNegative() != y.IsNegative()}; | 
|  | if (IsInfinite() || y.IsInfinite()) { | 
|  | if (IsZero() || y.IsZero()) { | 
|  | result.value = NotANumber(); // 0 * Inf -> NaN | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | } else { | 
|  | result.value = Infinity(isNegative); | 
|  | } | 
|  | } else { | 
|  | auto product{GetFraction().MultiplyUnsigned(y.GetFraction())}; | 
|  | std::int64_t exponent{CombineExponents(y, false)}; | 
|  | if (exponent < 1) { | 
|  | int rshift = 1 - exponent; | 
|  | exponent = 1; | 
|  | bool sticky{false}; | 
|  | if (rshift >= product.upper.bits + product.lower.bits) { | 
|  | sticky = !product.lower.IsZero() || !product.upper.IsZero(); | 
|  | } else if (rshift >= product.lower.bits) { | 
|  | sticky = !product.lower.IsZero() || | 
|  | !product.upper | 
|  | .IAND(product.upper.MASKR(rshift - product.lower.bits)) | 
|  | .IsZero(); | 
|  | } else { | 
|  | sticky = !product.lower.IAND(product.lower.MASKR(rshift)).IsZero(); | 
|  | } | 
|  | product.lower = product.lower.SHIFTRWithFill(product.upper, rshift); | 
|  | product.upper = product.upper.SHIFTR(rshift); | 
|  | if (sticky) { | 
|  | product.lower = product.lower.IBSET(0); | 
|  | } | 
|  | } | 
|  | int leadz{product.upper.LEADZ()}; | 
|  | if (leadz >= product.upper.bits) { | 
|  | leadz += product.lower.LEADZ(); | 
|  | } | 
|  | int lshift{leadz}; | 
|  | if (lshift > exponent - 1) { | 
|  | lshift = exponent - 1; | 
|  | } | 
|  | exponent -= lshift; | 
|  | product.upper = product.upper.SHIFTLWithFill(product.lower, lshift); | 
|  | product.lower = product.lower.SHIFTL(lshift); | 
|  | RoundingBits roundingBits{product.lower, product.lower.bits}; | 
|  | NormalizeAndRound(result, isNegative, exponent, product.upper, rounding, | 
|  | roundingBits, true /*multiply*/); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::Divide( | 
|  | const Real &y, Rounding rounding) const { | 
|  | ValueWithRealFlags<Real> result; | 
|  | if (IsNotANumber() || y.IsNotANumber()) { | 
|  | result.value = NotANumber(); // NaN / x -> NaN, x / NaN -> NaN | 
|  | if (IsSignalingNaN() || y.IsSignalingNaN()) { | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | } | 
|  | } else { | 
|  | bool isNegative{IsNegative() != y.IsNegative()}; | 
|  | if (IsInfinite()) { | 
|  | if (y.IsInfinite()) { | 
|  | result.value = NotANumber(); // Inf/Inf -> NaN | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | } else { // Inf/x -> Inf,  Inf/0 -> Inf | 
|  | result.value = Infinity(isNegative); | 
|  | } | 
|  | } else if (y.IsZero()) { | 
|  | if (IsZero()) { // 0/0 -> NaN | 
|  | result.value = NotANumber(); | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | } else { // x/0 -> Inf, Inf/0 -> Inf | 
|  | result.value = Infinity(isNegative); | 
|  | result.flags.set(RealFlag::DivideByZero); | 
|  | } | 
|  | } else if (IsZero() || y.IsInfinite()) { // 0/x, x/Inf -> 0 | 
|  | if (isNegative) { | 
|  | result.value = NegativeZero(); | 
|  | } | 
|  | } else { | 
|  | // dividend and divisor are both finite and nonzero numbers | 
|  | Fraction top{GetFraction()}, divisor{y.GetFraction()}; | 
|  | std::int64_t exponent{CombineExponents(y, true)}; | 
|  | Fraction quotient; | 
|  | bool msb{false}; | 
|  | if (!top.BTEST(top.bits - 1) || !divisor.BTEST(divisor.bits - 1)) { | 
|  | // One or two subnormals | 
|  | int topLshift{top.LEADZ()}; | 
|  | top = top.SHIFTL(topLshift); | 
|  | int divisorLshift{divisor.LEADZ()}; | 
|  | divisor = divisor.SHIFTL(divisorLshift); | 
|  | exponent += divisorLshift - topLshift; | 
|  | } | 
|  | for (int j{1}; j <= quotient.bits; ++j) { | 
|  | if (NextQuotientBit(top, msb, divisor)) { | 
|  | quotient = quotient.IBSET(quotient.bits - j); | 
|  | } | 
|  | } | 
|  | bool guard{NextQuotientBit(top, msb, divisor)}; | 
|  | bool round{NextQuotientBit(top, msb, divisor)}; | 
|  | bool sticky{msb || !top.IsZero()}; | 
|  | RoundingBits roundingBits{guard, round, sticky}; | 
|  | if (exponent < 1) { | 
|  | std::int64_t rshift{1 - exponent}; | 
|  | for (; rshift > 0; --rshift) { | 
|  | roundingBits.ShiftRight(quotient.BTEST(0)); | 
|  | quotient = quotient.SHIFTR(1); | 
|  | } | 
|  | exponent = 1; | 
|  | } | 
|  | NormalizeAndRound( | 
|  | result, isNegative, exponent, quotient, rounding, roundingBits); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::SQRT(Rounding rounding) const { | 
|  | ValueWithRealFlags<Real> result; | 
|  | if (IsNotANumber()) { | 
|  | result.value = NotANumber(); | 
|  | if (IsSignalingNaN()) { | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | } | 
|  | } else if (IsNegative()) { | 
|  | if (IsZero()) { | 
|  | // SQRT(-0) == -0 in IEEE-754. | 
|  | result.value = NegativeZero(); | 
|  | } else { | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | result.value = NotANumber(); | 
|  | } | 
|  | } else if (IsInfinite()) { | 
|  | // SQRT(+Inf) == +Inf | 
|  | result.value = Infinity(false); | 
|  | } else if (IsZero()) { | 
|  | result.value = PositiveZero(); | 
|  | } else { | 
|  | int expo{UnbiasedExponent()}; | 
|  | if (expo < -1 || expo > 1) { | 
|  | // Reduce the range to [0.5 .. 4.0) by dividing by an integral power | 
|  | // of four to avoid trouble with very large and very small values | 
|  | // (esp. truncation of subnormals). | 
|  | // SQRT(2**(2a) * x) = SQRT(2**(2a)) * SQRT(x) = 2**a * SQRT(x) | 
|  | Real scaled; | 
|  | int adjust{expo / 2}; | 
|  | scaled.Normalize(false, expo - 2 * adjust + exponentBias, GetFraction()); | 
|  | result = scaled.SQRT(rounding); | 
|  | result.value.Normalize(false, | 
|  | result.value.UnbiasedExponent() + adjust + exponentBias, | 
|  | result.value.GetFraction()); | 
|  | return result; | 
|  | } | 
|  | // (-1) <= expo <= 1; use it as a shift to set the desired square. | 
|  | using Extended = typename value::Integer<(binaryPrecision + 2)>; | 
|  | Extended goal{ | 
|  | Extended::ConvertUnsigned(GetFraction()).value.SHIFTL(expo + 1)}; | 
|  | // Calculate the exact square root by maximizing a value whose square | 
|  | // does not exceed the goal.  Use two extra bits of precision for | 
|  | // rounding. | 
|  | bool sticky{true}; | 
|  | Extended extFrac{}; | 
|  | for (int bit{Extended::bits - 1}; bit >= 0; --bit) { | 
|  | Extended next{extFrac.IBSET(bit)}; | 
|  | auto squared{next.MultiplyUnsigned(next)}; | 
|  | auto cmp{squared.upper.CompareUnsigned(goal)}; | 
|  | if (cmp == Ordering::Less) { | 
|  | extFrac = next; | 
|  | } else if (cmp == Ordering::Equal && squared.lower.IsZero()) { | 
|  | extFrac = next; | 
|  | sticky = false; | 
|  | break; // exact result | 
|  | } | 
|  | } | 
|  | RoundingBits roundingBits{extFrac.BTEST(1), extFrac.BTEST(0), sticky}; | 
|  | NormalizeAndRound(result, false, exponentBias, | 
|  | Fraction::ConvertUnsigned(extFrac.SHIFTR(2)).value, rounding, | 
|  | roundingBits); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::NEAREST(bool upward) const { | 
|  | ValueWithRealFlags<Real> result; | 
|  | if (IsFinite()) { | 
|  | Fraction fraction{GetFraction()}; | 
|  | int expo{Exponent()}; | 
|  | Fraction one{1}; | 
|  | Fraction nearest; | 
|  | bool isNegative{IsNegative()}; | 
|  | if (upward != isNegative) { // upward in magnitude | 
|  | auto next{fraction.AddUnsigned(one)}; | 
|  | if (next.carry) { | 
|  | ++expo; | 
|  | nearest = Fraction::Least(); // MSB only | 
|  | } else { | 
|  | nearest = next.value; | 
|  | } | 
|  | } else { // downward in magnitude | 
|  | if (IsZero()) { | 
|  | nearest = 1; // smallest magnitude negative subnormal | 
|  | isNegative = !isNegative; | 
|  | } else { | 
|  | auto sub1{fraction.SubtractSigned(one)}; | 
|  | if (sub1.overflow && expo > 1) { | 
|  | nearest = Fraction{0}.NOT(); | 
|  | --expo; | 
|  | } else { | 
|  | nearest = sub1.value; | 
|  | } | 
|  | } | 
|  | } | 
|  | result.flags = result.value.Normalize(isNegative, expo, nearest); | 
|  | } else { | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | result.value = *this; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // HYPOT(x,y) = SQRT(x**2 + y**2) by definition, but those squared intermediate | 
|  | // values are susceptible to over/underflow when computed naively. | 
|  | // Assuming that x>=y, calculate instead: | 
|  | //   HYPOT(x,y) = SQRT(x**2 * (1+(y/x)**2)) | 
|  | //              = ABS(x) * SQRT(1+(y/x)**2) | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::HYPOT( | 
|  | const Real &y, Rounding rounding) const { | 
|  | ValueWithRealFlags<Real> result; | 
|  | if (IsNotANumber() || y.IsNotANumber()) { | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | result.value = NotANumber(); | 
|  | } else if (ABS().Compare(y.ABS()) == Relation::Less) { | 
|  | return y.HYPOT(*this); | 
|  | } else if (IsZero()) { | 
|  | return result; // x==y==0 | 
|  | } else { | 
|  | auto yOverX{y.Divide(*this, rounding)}; // y/x | 
|  | bool inexact{yOverX.flags.test(RealFlag::Inexact)}; | 
|  | auto squared{yOverX.value.Multiply(yOverX.value, rounding)}; // (y/x)**2 | 
|  | inexact |= squared.flags.test(RealFlag::Inexact); | 
|  | Real one; | 
|  | one.Normalize(false, exponentBias, Fraction::MASKL(1)); // 1.0 | 
|  | auto sum{squared.value.Add(one, rounding)}; // 1.0 + (y/x)**2 | 
|  | inexact |= sum.flags.test(RealFlag::Inexact); | 
|  | auto sqrt{sum.value.SQRT()}; | 
|  | inexact |= sqrt.flags.test(RealFlag::Inexact); | 
|  | result = sqrt.value.Multiply(ABS(), rounding); | 
|  | if (inexact) { | 
|  | result.flags.set(RealFlag::Inexact); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // MOD(x,y) = x - AINT(x/y)*y in the standard; unfortunately, this definition | 
|  | // can be pretty inaccurate when x is much larger than y in magnitude due to | 
|  | // cancellation.  Implement instead with (essentially) arbitrary precision | 
|  | // long division, discarding the quotient and returning the remainder. | 
|  | // See runtime/numeric.cpp for more details. | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::MOD( | 
|  | const Real &p, Rounding rounding) const { | 
|  | ValueWithRealFlags<Real> result; | 
|  | if (IsNotANumber() || p.IsNotANumber() || IsInfinite()) { | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | result.value = NotANumber(); | 
|  | } else if (p.IsZero()) { | 
|  | result.flags.set(RealFlag::DivideByZero); | 
|  | result.value = NotANumber(); | 
|  | } else if (p.IsInfinite()) { | 
|  | result.value = *this; | 
|  | } else { | 
|  | result.value = ABS(); | 
|  | auto pAbs{p.ABS()}; | 
|  | Real half, adj; | 
|  | half.Normalize(false, exponentBias - 1, Fraction::MASKL(1)); // 0.5 | 
|  | for (adj.Normalize(false, Exponent(), pAbs.GetFraction()); | 
|  | result.value.Compare(pAbs) != Relation::Less; | 
|  | adj = adj.Multiply(half).value) { | 
|  | if (result.value.Compare(adj) != Relation::Less) { | 
|  | result.value = | 
|  | result.value.Subtract(adj, rounding).AccumulateFlags(result.flags); | 
|  | if (result.value.IsZero()) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (IsNegative()) { | 
|  | result.value = result.value.Negate(); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // MODULO(x,y) = x - FLOOR(x/y)*y in the standard; here, it is defined | 
|  | // in terms of MOD() with adjustment of the result. | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::MODULO( | 
|  | const Real &p, Rounding rounding) const { | 
|  | ValueWithRealFlags<Real> result{MOD(p, rounding)}; | 
|  | if (IsNegative() != p.IsNegative()) { | 
|  | if (result.value.IsZero()) { | 
|  | result.value = result.value.Negate(); | 
|  | } else { | 
|  | result.value = | 
|  | result.value.Add(p, rounding).AccumulateFlags(result.flags); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::DIM( | 
|  | const Real &y, Rounding rounding) const { | 
|  | ValueWithRealFlags<Real> result; | 
|  | if (IsNotANumber() || y.IsNotANumber()) { | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | result.value = NotANumber(); | 
|  | } else if (Compare(y) == Relation::Greater) { | 
|  | result = Subtract(y, rounding); | 
|  | } else { | 
|  | // result is already zero | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::ToWholeNumber( | 
|  | common::RoundingMode mode) const { | 
|  | ValueWithRealFlags<Real> result{*this}; | 
|  | if (IsNotANumber()) { | 
|  | result.flags.set(RealFlag::InvalidArgument); | 
|  | result.value = NotANumber(); | 
|  | } else if (IsInfinite()) { | 
|  | result.flags.set(RealFlag::Overflow); | 
|  | } else { | 
|  | constexpr int noClipExponent{exponentBias + binaryPrecision - 1}; | 
|  | if (Exponent() < noClipExponent) { | 
|  | Real adjust; // ABS(EPSILON(adjust)) == 0.5 | 
|  | adjust.Normalize(IsSignBitSet(), noClipExponent, Fraction::MASKL(1)); | 
|  | // Compute ival=(*this + adjust), losing any fractional bits; keep flags | 
|  | result = Add(adjust, Rounding{mode}); | 
|  | result.flags.reset(RealFlag::Inexact); // result *is* exact | 
|  | // Return (ival-adjust) with original sign in case we've generated a zero. | 
|  | result.value = | 
|  | result.value.Subtract(adjust, Rounding{common::RoundingMode::ToZero}) | 
|  | .value.SIGN(*this); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | RealFlags Real<W, P>::Normalize(bool negative, int exponent, | 
|  | const Fraction &fraction, Rounding rounding, RoundingBits *roundingBits) { | 
|  | int lshift{fraction.LEADZ()}; | 
|  | if (lshift == fraction.bits /* fraction is zero */ && | 
|  | (!roundingBits || roundingBits->empty())) { | 
|  | // No fraction, no rounding bits -> +/-0.0 | 
|  | exponent = lshift = 0; | 
|  | } else if (lshift < exponent) { | 
|  | exponent -= lshift; | 
|  | } else if (exponent > 0) { | 
|  | lshift = exponent - 1; | 
|  | exponent = 0; | 
|  | } else if (lshift == 0) { | 
|  | exponent = 1; | 
|  | } else { | 
|  | lshift = 0; | 
|  | } | 
|  | if (exponent >= maxExponent) { | 
|  | // Infinity or overflow | 
|  | if (rounding.mode == common::RoundingMode::TiesToEven || | 
|  | rounding.mode == common::RoundingMode::TiesAwayFromZero || | 
|  | (rounding.mode == common::RoundingMode::Up && !negative) || | 
|  | (rounding.mode == common::RoundingMode::Down && negative)) { | 
|  | word_ = Word{maxExponent}.SHIFTL(significandBits); // Inf | 
|  | } else { | 
|  | // directed rounding: round to largest finite value rather than infinity | 
|  | // (x86 does this, not sure whether it's standard behavior) | 
|  | word_ = Word{word_.MASKR(word_.bits - 1)}.IBCLR(significandBits); | 
|  | } | 
|  | if (negative) { | 
|  | word_ = word_.IBSET(bits - 1); | 
|  | } | 
|  | RealFlags flags{RealFlag::Overflow}; | 
|  | if (!fraction.IsZero()) { | 
|  | flags.set(RealFlag::Inexact); | 
|  | } | 
|  | return flags; | 
|  | } | 
|  | word_ = Word::ConvertUnsigned(fraction).value; | 
|  | if (lshift > 0) { | 
|  | word_ = word_.SHIFTL(lshift); | 
|  | if (roundingBits) { | 
|  | for (; lshift > 0; --lshift) { | 
|  | if (roundingBits->ShiftLeft()) { | 
|  | word_ = word_.IBSET(lshift - 1); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | if constexpr (isImplicitMSB) { | 
|  | word_ = word_.IBCLR(significandBits); | 
|  | } | 
|  | word_ = word_.IOR(Word{exponent}.SHIFTL(significandBits)); | 
|  | if (negative) { | 
|  | word_ = word_.IBSET(bits - 1); | 
|  | } | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | RealFlags Real<W, P>::Round( | 
|  | Rounding rounding, const RoundingBits &bits, bool multiply) { | 
|  | int origExponent{Exponent()}; | 
|  | RealFlags flags; | 
|  | bool inexact{!bits.empty()}; | 
|  | if (inexact) { | 
|  | flags.set(RealFlag::Inexact); | 
|  | } | 
|  | if (origExponent < maxExponent && | 
|  | bits.MustRound(rounding, IsNegative(), word_.BTEST(0) /* is odd */)) { | 
|  | typename Fraction::ValueWithCarry sum{ | 
|  | GetFraction().AddUnsigned(Fraction{}, true)}; | 
|  | int newExponent{origExponent}; | 
|  | if (sum.carry) { | 
|  | // The fraction was all ones before rounding; sum.value is now zero | 
|  | sum.value = sum.value.IBSET(binaryPrecision - 1); | 
|  | if (++newExponent >= maxExponent) { | 
|  | flags.set(RealFlag::Overflow); // rounded away to an infinity | 
|  | } | 
|  | } | 
|  | flags |= Normalize(IsNegative(), newExponent, sum.value); | 
|  | } | 
|  | if (inexact && origExponent == 0) { | 
|  | // inexact subnormal input: signal Underflow unless in an x86-specific | 
|  | // edge case | 
|  | if (rounding.x86CompatibleBehavior && Exponent() != 0 && multiply && | 
|  | bits.sticky() && | 
|  | (bits.guard() || | 
|  | (rounding.mode != common::RoundingMode::Up && | 
|  | rounding.mode != common::RoundingMode::Down))) { | 
|  | // x86 edge case in which Underflow fails to signal when a subnormal | 
|  | // inexact multiplication product rounds to a normal result when | 
|  | // the guard bit is set or we're not using directed rounding | 
|  | } else { | 
|  | flags.set(RealFlag::Underflow); | 
|  | } | 
|  | } | 
|  | return flags; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | void Real<W, P>::NormalizeAndRound(ValueWithRealFlags<Real> &result, | 
|  | bool isNegative, int exponent, const Fraction &fraction, Rounding rounding, | 
|  | RoundingBits roundingBits, bool multiply) { | 
|  | result.flags |= result.value.Normalize( | 
|  | isNegative, exponent, fraction, rounding, &roundingBits); | 
|  | result.flags |= result.value.Round(rounding, roundingBits, multiply); | 
|  | } | 
|  |  | 
|  | inline enum decimal::FortranRounding MapRoundingMode( | 
|  | common::RoundingMode rounding) { | 
|  | switch (rounding) { | 
|  | case common::RoundingMode::TiesToEven: | 
|  | break; | 
|  | case common::RoundingMode::ToZero: | 
|  | return decimal::RoundToZero; | 
|  | case common::RoundingMode::Down: | 
|  | return decimal::RoundDown; | 
|  | case common::RoundingMode::Up: | 
|  | return decimal::RoundUp; | 
|  | case common::RoundingMode::TiesAwayFromZero: | 
|  | return decimal::RoundCompatible; | 
|  | } | 
|  | return decimal::RoundNearest; // dodge gcc warning about lack of result | 
|  | } | 
|  |  | 
|  | inline RealFlags MapFlags(decimal::ConversionResultFlags flags) { | 
|  | RealFlags result; | 
|  | if (flags & decimal::Overflow) { | 
|  | result.set(RealFlag::Overflow); | 
|  | } | 
|  | if (flags & decimal::Inexact) { | 
|  | result.set(RealFlag::Inexact); | 
|  | } | 
|  | if (flags & decimal::Invalid) { | 
|  | result.set(RealFlag::InvalidArgument); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | ValueWithRealFlags<Real<W, P>> Real<W, P>::Read( | 
|  | const char *&p, Rounding rounding) { | 
|  | auto converted{ | 
|  | decimal::ConvertToBinary<P>(p, MapRoundingMode(rounding.mode))}; | 
|  | const auto *value{reinterpret_cast<Real<W, P> *>(&converted.binary)}; | 
|  | return {*value, MapFlags(converted.flags)}; | 
|  | } | 
|  |  | 
|  | template <typename W, int P> std::string Real<W, P>::DumpHexadecimal() const { | 
|  | if (IsNotANumber()) { | 
|  | return "NaN0x"s + word_.Hexadecimal(); | 
|  | } else if (IsNegative()) { | 
|  | return "-"s + Negate().DumpHexadecimal(); | 
|  | } else if (IsInfinite()) { | 
|  | return "Inf"s; | 
|  | } else if (IsZero()) { | 
|  | return "0.0"s; | 
|  | } else { | 
|  | Fraction frac{GetFraction()}; | 
|  | std::string result{"0x"}; | 
|  | char intPart = '0' + frac.BTEST(frac.bits - 1); | 
|  | result += intPart; | 
|  | result += '.'; | 
|  | int trailz{frac.TRAILZ()}; | 
|  | if (trailz >= frac.bits - 1) { | 
|  | result += '0'; | 
|  | } else { | 
|  | int remainingBits{frac.bits - 1 - trailz}; | 
|  | int wholeNybbles{remainingBits / 4}; | 
|  | int lostBits{remainingBits - 4 * wholeNybbles}; | 
|  | if (wholeNybbles > 0) { | 
|  | std::string fracHex{frac.SHIFTR(trailz + lostBits) | 
|  | .IAND(frac.MASKR(4 * wholeNybbles)) | 
|  | .Hexadecimal()}; | 
|  | std::size_t field = wholeNybbles; | 
|  | if (fracHex.size() < field) { | 
|  | result += std::string(field - fracHex.size(), '0'); | 
|  | } | 
|  | result += fracHex; | 
|  | } | 
|  | if (lostBits > 0) { | 
|  | result += frac.SHIFTR(trailz) | 
|  | .IAND(frac.MASKR(lostBits)) | 
|  | .SHIFTL(4 - lostBits) | 
|  | .Hexadecimal(); | 
|  | } | 
|  | } | 
|  | result += 'p'; | 
|  | int exponent = Exponent() - exponentBias; | 
|  | if (intPart == '0') { | 
|  | exponent += 1; | 
|  | } | 
|  | result += Integer<32>{exponent}.SignedDecimal(); | 
|  | return result; | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename W, int P> | 
|  | llvm::raw_ostream &Real<W, P>::AsFortran( | 
|  | llvm::raw_ostream &o, int kind, bool minimal) const { | 
|  | if (IsNotANumber()) { | 
|  | o << "(0._" << kind << "/0.)"; | 
|  | } else if (IsInfinite()) { | 
|  | if (IsNegative()) { | 
|  | o << "(-1._" << kind << "/0.)"; | 
|  | } else { | 
|  | o << "(1._" << kind << "/0.)"; | 
|  | } | 
|  | } else { | 
|  | using B = decimal::BinaryFloatingPointNumber<P>; | 
|  | B value{word_.template ToUInt<typename B::RawType>()}; | 
|  | char buffer[common::MaxDecimalConversionDigits(P) + | 
|  | EXTRA_DECIMAL_CONVERSION_SPACE]; | 
|  | decimal::DecimalConversionFlags flags{}; // default: exact representation | 
|  | if (minimal) { | 
|  | flags = decimal::Minimize; | 
|  | } | 
|  | auto result{decimal::ConvertToDecimal<P>(buffer, sizeof buffer, flags, | 
|  | static_cast<int>(sizeof buffer), decimal::RoundNearest, value)}; | 
|  | const char *p{result.str}; | 
|  | if (DEREF(p) == '-' || *p == '+') { | 
|  | o << *p++; | 
|  | } | 
|  | int expo{result.decimalExponent}; | 
|  | if (*p != '0') { | 
|  | --expo; | 
|  | } | 
|  | o << *p << '.' << (p + 1); | 
|  | if (expo != 0) { | 
|  | o << 'e' << expo; | 
|  | } | 
|  | o << '_' << kind; | 
|  | } | 
|  | return o; | 
|  | } | 
|  |  | 
|  | // 16.9.180 | 
|  | template <typename W, int P> Real<W, P> Real<W, P>::RRSPACING() const { | 
|  | if (IsNotANumber()) { | 
|  | return *this; | 
|  | } else if (IsInfinite()) { | 
|  | return NotANumber(); | 
|  | } else { | 
|  | Real result; | 
|  | result.Normalize(false, binaryPrecision + exponentBias - 1, GetFraction()); | 
|  | return result; | 
|  | } | 
|  | } | 
|  |  | 
|  | // 16.9.180 | 
|  | template <typename W, int P> Real<W, P> Real<W, P>::SPACING() const { | 
|  | if (IsNotANumber()) { | 
|  | return *this; | 
|  | } else if (IsInfinite()) { | 
|  | return NotANumber(); | 
|  | } else if (IsZero() || IsSubnormal()) { | 
|  | return TINY(); // mandated by standard | 
|  | } else { | 
|  | Real result; | 
|  | result.Normalize(false, Exponent(), Fraction::MASKR(1)); | 
|  | return result.IsZero() ? TINY() : result; | 
|  | } | 
|  | } | 
|  |  | 
|  | // 16.9.171 | 
|  | template <typename W, int P> | 
|  | Real<W, P> Real<W, P>::SET_EXPONENT(std::int64_t expo) const { | 
|  | if (IsNotANumber()) { | 
|  | return *this; | 
|  | } else if (IsInfinite()) { | 
|  | return NotANumber(); | 
|  | } else if (IsZero()) { | 
|  | return *this; | 
|  | } else { | 
|  | return SCALE(Integer<64>(expo - UnbiasedExponent() - 1)).value; | 
|  | } | 
|  | } | 
|  |  | 
|  | // 16.9.171 | 
|  | template <typename W, int P> Real<W, P> Real<W, P>::FRACTION() const { | 
|  | return SET_EXPONENT(0); | 
|  | } | 
|  |  | 
|  | template class Real<Integer<16>, 11>; | 
|  | template class Real<Integer<16>, 8>; | 
|  | template class Real<Integer<32>, 24>; | 
|  | template class Real<Integer<64>, 53>; | 
|  | template class Real<X87IntegerContainer, 64>; | 
|  | template class Real<Integer<128>, 113>; | 
|  | } // namespace Fortran::evaluate::value |