[flang] COMPLEX folding

Original-commit: flang-compiler/f18@6f1ef45b2f
Reviewed-on: https://github.com/flang-compiler/f18/pull/162
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-07-25 15:02:21 -07:00
parent bd146ed3e8
commit b861018e3a
8 changed files with 230 additions and 84 deletions

View File

@ -82,6 +82,8 @@ template<typename A> struct ValueWithRealFlags {
ENUM_CLASS(Rounding, TiesToEven, ToZero, Down, Up, TiesAwayFromZero)
static constexpr Rounding defaultRounding{Rounding::TiesToEven};
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
constexpr bool IsHostLittleEndian{false};
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__

View File

@ -17,36 +17,40 @@
namespace Fortran::evaluate::value {
template<typename R>
ValueWithRealFlags<Complex<R>> Complex<R>::Add(const Complex &that) const {
ValueWithRealFlags<Complex<R>> Complex<R>::Add(
const Complex &that, Rounding rounding) const {
RealFlags flags;
Part reSum{re_.Add(that.re_).AccumulateFlags(flags)};
Part imSum{im_.Add(that.im_).AccumulateFlags(flags)};
Part reSum{re_.Add(that.re_, rounding).AccumulateFlags(flags)};
Part imSum{im_.Add(that.im_, rounding).AccumulateFlags(flags)};
return {Complex{reSum, imSum}, flags};
}
template<typename R>
ValueWithRealFlags<Complex<R>> Complex<R>::Subtract(const Complex &that) const {
ValueWithRealFlags<Complex<R>> Complex<R>::Subtract(
const Complex &that, Rounding rounding) const {
RealFlags flags;
Part reDiff{re_.Subtract(that.re_).AccumulateFlags(flags)};
Part imDiff{im_.Subtract(that.im_).AccumulateFlags(flags)};
Part reDiff{re_.Subtract(that.re_, rounding).AccumulateFlags(flags)};
Part imDiff{im_.Subtract(that.im_, rounding).AccumulateFlags(flags)};
return {Complex{reDiff, imDiff}, flags};
}
template<typename R>
ValueWithRealFlags<Complex<R>> Complex<R>::Multiply(const Complex &that) const {
ValueWithRealFlags<Complex<R>> Complex<R>::Multiply(
const Complex &that, Rounding rounding) const {
// (a + ib)*(c + id) -> ac - bd + i(ad + bc)
RealFlags flags;
Part ac{re_.Multiply(that.re_).AccumulateFlags(flags)};
Part bd{im_.Multiply(that.im_).AccumulateFlags(flags)};
Part ad{re_.Multiply(that.im_).AccumulateFlags(flags)};
Part bc{im_.Multiply(that.re_).AccumulateFlags(flags)};
Part acbd{ac.Subtract(bd).AccumulateFlags(flags)};
Part adbc{ad.Add(bc).AccumulateFlags(flags)};
Part ac{re_.Multiply(that.re_, rounding).AccumulateFlags(flags)};
Part bd{im_.Multiply(that.im_, rounding).AccumulateFlags(flags)};
Part ad{re_.Multiply(that.im_, rounding).AccumulateFlags(flags)};
Part bc{im_.Multiply(that.re_, rounding).AccumulateFlags(flags)};
Part acbd{ac.Subtract(bd, rounding).AccumulateFlags(flags)};
Part adbc{ad.Add(bc, rounding).AccumulateFlags(flags)};
return {Complex{acbd, adbc}, flags};
}
template<typename R>
ValueWithRealFlags<Complex<R>> Complex<R>::Divide(const Complex &that) const {
ValueWithRealFlags<Complex<R>> Complex<R>::Divide(
const Complex &that, Rounding rounding) const {
// (a + ib)/(c + id) -> [(a+ib)*(c-id)] / [(c+id)*(c-id)]
// -> [ac+bd+i(bc-ad)] / (cc+dd)
// -> ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
@ -55,30 +59,30 @@ ValueWithRealFlags<Complex<R>> Complex<R>::Divide(const Complex &that) const {
RealFlags flags;
bool cGEd{that.re_.ABS().Compare(that.im_.ABS()) != Relation::Less};
if (cGEd) {
scale = that.im_.Divide(that.re_).AccumulateFlags(flags);
scale = that.im_.Divide(that.re_, rounding).AccumulateFlags(flags);
} else {
scale = that.re_.Divide(that.im_).AccumulateFlags(flags);
scale = that.re_.Divide(that.im_, rounding).AccumulateFlags(flags);
}
Part den;
if (cGEd) {
Part dS{scale.Multiply(that.im_).AccumulateFlags(flags)};
den = dS.Add(that.re_).AccumulateFlags(flags);
Part dS{scale.Multiply(that.im_, rounding).AccumulateFlags(flags)};
den = dS.Add(that.re_, rounding).AccumulateFlags(flags);
} else {
Part cS{scale.Multiply(that.re_).AccumulateFlags(flags)};
den = cS.Add(that.im_).AccumulateFlags(flags);
Part cS{scale.Multiply(that.re_, rounding).AccumulateFlags(flags)};
den = cS.Add(that.im_, rounding).AccumulateFlags(flags);
}
Part aS{scale.Multiply(re_).AccumulateFlags(flags)};
Part bS{scale.Multiply(im_).AccumulateFlags(flags)};
Part aS{scale.Multiply(re_, rounding).AccumulateFlags(flags)};
Part bS{scale.Multiply(im_, rounding).AccumulateFlags(flags)};
Part re1, im1;
if (cGEd) {
re1 = re_.Add(bS).AccumulateFlags(flags);
im1 = im_.Subtract(aS).AccumulateFlags(flags);
re1 = re_.Add(bS, rounding).AccumulateFlags(flags);
im1 = im_.Subtract(aS, rounding).AccumulateFlags(flags);
} else {
re1 = aS.Add(im_).AccumulateFlags(flags);
im1 = bS.Subtract(re_).AccumulateFlags(flags);
re1 = aS.Add(im_, rounding).AccumulateFlags(flags);
im1 = bS.Subtract(re_, rounding).AccumulateFlags(flags);
}
Part re{re1.Divide(den).AccumulateFlags(flags)};
Part im{im1.Divide(den).AccumulateFlags(flags)};
Part re{re1.Divide(den, rounding).AccumulateFlags(flags)};
Part im{im1.Divide(den, rounding).AccumulateFlags(flags)};
return {Complex{re, im}, flags};
}

View File

@ -29,6 +29,8 @@ public:
constexpr Complex(const Complex &) = default;
constexpr Complex(const Part &r, const Part &i) : re_{r}, im_{i} {}
explicit constexpr Complex(const Part &r) : re_{r} {}
constexpr Complex &operator=(const Complex &) = default;
constexpr Complex &operator=(Complex &&) = default;
constexpr const Part &REAL() const { return re_; }
constexpr const Part &AIMAG() const { return im_; }
@ -40,10 +42,43 @@ public:
im_.Compare(that.im_) == Relation::Equal;
}
ValueWithRealFlags<Complex> Add(const Complex &) const;
ValueWithRealFlags<Complex> Subtract(const Complex &) const;
ValueWithRealFlags<Complex> Multiply(const Complex &) const;
ValueWithRealFlags<Complex> Divide(const Complex &) const;
constexpr bool IsZero() const { return re_.IsZero() || im_.IsZero(); }
constexpr bool IsInfinite() const {
return re_.IsInfinite() || im_.IsInfinite();
}
constexpr bool IsNotANumber() const {
return re_.IsNotANumber() || im_.IsNotANumber();
}
constexpr bool IsSignalingNaN() const {
return re_.IsSignalingNaN() || im_.IsSignalingNaN();
}
template<typename INT>
static ValueWithRealFlags<Complex> FromInteger(
const INT &n, Rounding rounding = defaultRounding) {
ValueWithRealFlags<Complex> result;
result.value.re_ =
Part::FromInteger(n, rounding).AccumulateFlags(result.flags);
return result;
}
ValueWithRealFlags<Complex> Add(
const Complex &, Rounding rounding = defaultRounding) const;
ValueWithRealFlags<Complex> Subtract(
const Complex &, Rounding rounding = defaultRounding) const;
ValueWithRealFlags<Complex> Multiply(
const Complex &, Rounding rounding = defaultRounding) const;
ValueWithRealFlags<Complex> Divide(
const Complex &, Rounding rounding = defaultRounding) const;
constexpr Complex FlushDenormalToZero() const {
return {re_.FlushDenormalToZero(), im_.FlushDenormalToZero()};
}
static constexpr Complex NaN() { return {Part::NaN(), Part::NaN()}; }
std::string DumpHexadecimal() const;
// TODO: (C)ABS once Real::HYPOT is done

View File

@ -215,7 +215,7 @@ auto Unary<CRTP, RESULT, A>::Fold(FoldingContext &context)
if (std::optional<OperandScalarConstant> c{operand_->Fold(context)}) {
return static_cast<CRTP *>(this)->FoldScalar(context, *c);
}
return {};
return std::nullopt;
}
template<typename CRTP, typename RESULT, typename A, typename B>
@ -226,7 +226,7 @@ auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context)
if (lc.has_value() && rc.has_value()) {
return static_cast<CRTP *>(this)->FoldScalar(context, *lc, *rc);
}
return {};
return std::nullopt;
}
template<int KIND>
@ -237,7 +237,7 @@ auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
auto converted{Scalar::ConvertSigned(x)};
if (converted.overflow) {
context.messages.Say("integer conversion overflowed"_en_US);
return {};
return std::nullopt;
}
return {std::move(converted.value)};
},
@ -252,12 +252,12 @@ auto IntegerExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
auto converted{x.template ToInteger<Scalar>()};
if (converted.flags.test(RealFlag::Overflow)) {
context.messages.Say("real->integer conversion overflowed"_en_US);
return {};
return std::nullopt;
}
if (converted.flags.test(RealFlag::InvalidArgument)) {
context.messages.Say(
"real->integer conversion: invalid argument"_en_US);
return {};
return std::nullopt;
}
return {std::move(converted.value)};
},
@ -270,7 +270,7 @@ auto IntegerExpr<KIND>::Negate::FoldScalar(
auto negated{c.Negate()};
if (negated.overflow) {
context.messages.Say("integer negation overflowed"_en_US);
return {};
return std::nullopt;
}
return {std::move(negated.value)};
}
@ -281,7 +281,7 @@ auto IntegerExpr<KIND>::Add::FoldScalar(FoldingContext &context,
auto sum{a.AddSigned(b)};
if (sum.overflow) {
context.messages.Say("integer addition overflowed"_en_US);
return {};
return std::nullopt;
}
return {std::move(sum.value)};
}
@ -292,7 +292,7 @@ auto IntegerExpr<KIND>::Subtract::FoldScalar(FoldingContext &context,
auto diff{a.SubtractSigned(b)};
if (diff.overflow) {
context.messages.Say("integer subtraction overflowed"_en_US);
return {};
return std::nullopt;
}
return {std::move(diff.value)};
}
@ -303,7 +303,7 @@ auto IntegerExpr<KIND>::Multiply::FoldScalar(FoldingContext &context,
auto product{a.MultiplySigned(b)};
if (product.SignedMultiplicationOverflowed()) {
context.messages.Say("integer multiplication overflowed"_en_US);
return {};
return std::nullopt;
}
return {std::move(product.lower)};
}
@ -314,11 +314,11 @@ auto IntegerExpr<KIND>::Divide::FoldScalar(FoldingContext &context,
auto qr{a.DivideSigned(b)};
if (qr.divisionByZero) {
context.messages.Say("integer division by zero"_en_US);
return {};
return std::nullopt;
}
if (qr.overflow) {
context.messages.Say("integer division overflowed"_en_US);
return {};
return std::nullopt;
}
return {std::move(qr.quotient)};
}
@ -329,15 +329,15 @@ auto IntegerExpr<KIND>::Power::FoldScalar(FoldingContext &context,
typename Scalar::PowerWithErrors power{a.Power(b)};
if (power.divisionByZero) {
context.messages.Say("zero to negative power"_en_US);
return {};
return std::nullopt;
}
if (power.overflow) {
context.messages.Say("integer power overflowed"_en_US);
return {};
return std::nullopt;
}
if (power.zeroToZero) {
context.messages.Say("integer 0**0"_en_US);
return {};
return std::nullopt;
}
return {std::move(power.power)};
}
@ -375,7 +375,7 @@ auto IntegerExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
return c;
}
}
return {};
return std::nullopt;
},
u_);
}
@ -465,7 +465,7 @@ auto RealExpr<KIND>::Divide::FoldScalar(FoldingContext &context,
template<int KIND>
auto RealExpr<KIND>::Power::FoldScalar(FoldingContext &context, const Scalar &a,
const Scalar &b) -> std::optional<Scalar> {
return {}; // TODO
return std::nullopt; // TODO
}
template<int KIND>
@ -522,28 +522,108 @@ auto RealExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
if constexpr (evaluate::FoldableTrait<Ty>) {
auto c{x.Fold(context)};
if (c.has_value()) {
if (context.flushDenormalsToZero && c->IsDenormal()) {
u_ = Scalar{};
} else {
u_ = *c;
if (context.flushDenormalsToZero) {
*c = c->FlushDenormalToZero();
}
u_ = *c;
return c;
}
}
return {};
return std::nullopt;
},
u_);
}
template<int KIND>
auto ComplexExpr<KIND>::Negate::FoldScalar(
FoldingContext &context, const Scalar &c) -> std::optional<Scalar> {
return {c.Negate()};
}
template<int KIND>
auto ComplexExpr<KIND>::Add::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto sum{a.Add(b, context.rounding)};
RealFlagWarnings(context, sum.flags, "complex addition");
return {std::move(sum.value)};
}
template<int KIND>
auto ComplexExpr<KIND>::Subtract::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto difference{a.Subtract(b, context.rounding)};
RealFlagWarnings(context, difference.flags, "complex subtraction");
return {std::move(difference.value)};
}
template<int KIND>
auto ComplexExpr<KIND>::Multiply::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto product{a.Multiply(b, context.rounding)};
RealFlagWarnings(context, product.flags, "complex multiplication");
return {std::move(product.value)};
}
template<int KIND>
auto ComplexExpr<KIND>::Divide::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto quotient{a.Divide(b, context.rounding)};
RealFlagWarnings(context, quotient.flags, "complex division");
return {std::move(quotient.value)};
}
template<int KIND>
auto ComplexExpr<KIND>::Power::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
return std::nullopt; // TODO
}
template<int KIND>
auto ComplexExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
const Scalar &a, const ScalarConstant<Category::Integer> &b)
-> std::optional<Scalar> {
return std::visit(
[&](const auto &pow) -> std::optional<Scalar> {
auto power{evaluate::IntPower(a, pow)};
RealFlagWarnings(context, power.flags, "raising to integer power");
return {std::move(power.value)};
},
b.u);
}
template<int KIND>
auto ComplexExpr<KIND>::CMPLX::FoldScalar(FoldingContext &context,
const PartScalar &a, const PartScalar &b) -> std::optional<Scalar> {
return {Scalar{a, b}};
}
template<int KIND>
auto ComplexExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
return {}; // TODO
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
using Ty = typename std::decay<decltype(x)>::type;
if constexpr (std::is_same_v<Ty, Scalar>) {
return {x};
}
if constexpr (evaluate::FoldableTrait<Ty>) {
auto c{x.Fold(context)};
if (c.has_value()) {
if (context.flushDenormalsToZero) {
*c = c->FlushDenormalToZero();
}
u_ = *c;
return c;
}
}
return std::nullopt;
},
u_);
}
template<int KIND>
auto CharacterExpr<KIND>::Fold(FoldingContext &context)
-> std::optional<Scalar> {
return {}; // TODO
return std::nullopt; // TODO
}
template<typename A>
@ -574,11 +654,11 @@ auto Comparison<A>::FoldScalar(FoldingContext &c,
case Relation::Greater:
return {opr == RelationalOperator::NE || opr == RelationalOperator::GE ||
opr == RelationalOperator::GT};
case Relation::Unordered: return {};
case Relation::Unordered: return std::nullopt;
}
}
// TODO complex and character comparisons
return {};
return std::nullopt;
}
template<int KIND>
@ -626,7 +706,7 @@ auto LogicalExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
return c;
}
}
return {};
return std::nullopt;
},
u_);
}
@ -637,7 +717,7 @@ std::optional<GenericScalar> GenericExpr::ScalarValue() const {
if (auto c{x.ScalarValue()}) {
return {GenericScalar{std::move(*c)}};
}
return {};
return std::nullopt;
},
u);
}
@ -649,9 +729,7 @@ auto Expr<AnyKindType<CAT>>::ScalarValue() const -> std::optional<Scalar> {
if (auto c{x.ScalarValue()}) {
return {Scalar{std::move(*c)}};
}
std::optional<Scalar> avoidBogusGCCWarning; // ... with return {};
return avoidBogusGCCWarning;
;
return std::nullopt;
},
u);
}
@ -664,9 +742,7 @@ auto Expr<AnyKindType<CAT>>::Fold(FoldingContext &context)
if (auto c{x.Fold(context)}) {
return {Scalar{std::move(*c)}};
}
std::optional<Scalar> avoidBogusGCCWarning; // ... with return {};
return avoidBogusGCCWarning;
;
return std::nullopt;
},
u);
}
@ -677,7 +753,7 @@ std::optional<GenericScalar> GenericExpr::Fold(FoldingContext &context) {
if (auto c{x.Fold(context)}) {
return {GenericScalar{std::move(*c)}};
}
return {};
return std::nullopt;
},
u);
}

View File

@ -36,7 +36,7 @@ namespace Fortran::evaluate {
CLASS_TRAIT(FoldableTrait);
struct FoldingContext {
parser::ContextualMessages &messages;
Rounding rounding{Rounding::TiesToEven};
Rounding rounding{defaultRounding};
bool flushDenormalsToZero{false};
};
@ -330,31 +330,52 @@ public:
template<typename CRTP> using Bin = Binary<CRTP, Result>;
struct Parentheses : public Un<Parentheses> {
using Un<Parentheses>::Un;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &x) {
return {x};
}
};
struct Negate : public Un<Negate> {
using Un<Negate>::Un;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &);
};
struct Add : public Bin<Add> {
using Bin<Add>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
};
struct Subtract : public Bin<Subtract> {
using Bin<Subtract>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
};
struct Multiply : public Bin<Multiply> {
using Bin<Multiply>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
};
struct Divide : public Bin<Divide> {
using Bin<Divide>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
};
struct Power : public Bin<Power> {
using Bin<Power>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
};
struct IntPower
: public Binary<IntPower, Result, AnyKindType<Category::Integer>> {
using Binary<IntPower, Result, AnyKindType<Category::Integer>>::Binary;
: public Binary<IntPower, Result, Result, AnyKindType<Category::Integer>> {
using Binary<IntPower, Result, Result,
AnyKindType<Category::Integer>>::Binary;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &,
const ScalarConstant<Category::Integer> &);
};
struct CMPLX : public Binary<CMPLX, Result, Type<Category::Real, KIND>> {
using Binary<CMPLX, Result, Type<Category::Real, KIND>>::Binary;
using Part = Type<Category::Real, KIND>;
using PartScalar = typename Part::Value;
struct CMPLX : public Binary<CMPLX, Result, Part> {
using Binary<CMPLX, Result, Part>::Binary;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const PartScalar &, const PartScalar &);
};
CLASS_BOILERPLATE(Expr)

View File

@ -22,8 +22,8 @@
namespace Fortran::evaluate {
template<typename REAL, typename INT>
ValueWithRealFlags<REAL> IntPower(const REAL &base, const INT &power,
Rounding rounding = Rounding::TiesToEven) {
ValueWithRealFlags<REAL> IntPower(
const REAL &base, const INT &power, Rounding rounding = defaultRounding) {
REAL one{REAL::FromInteger(INT{1}).value};
ValueWithRealFlags<REAL> result;
result.value = one;

View File

@ -50,6 +50,7 @@ public:
constexpr Real(const Real &) = default;
constexpr Real(const Word &bits) : word_{bits} {}
constexpr Real &operator=(const Real &) = default;
constexpr Real &operator=(Real &&) = default;
// TODO: facility to flush denormal results to zero
// TODO AINT/ANINT, CEILING, FLOOR, DIM, MAX, MIN, DPROD, FRACTION
@ -87,20 +88,20 @@ public:
Relation Compare(const Real &) const;
ValueWithRealFlags<Real> Add(
const Real &, Rounding rounding = Rounding::TiesToEven) const;
const Real &, Rounding rounding = defaultRounding) const;
ValueWithRealFlags<Real> Subtract(
const Real &y, Rounding rounding = Rounding::TiesToEven) const {
const Real &y, Rounding rounding = defaultRounding) const {
return Add(y.Negate(), rounding);
}
ValueWithRealFlags<Real> Multiply(
const Real &, Rounding rounding = Rounding::TiesToEven) const;
const Real &, Rounding rounding = defaultRounding) const;
ValueWithRealFlags<Real> Divide(
const Real &, Rounding rounding = Rounding::TiesToEven) const;
const Real &, Rounding rounding = defaultRounding) const;
// SQRT(x**2 + y**2) but computed so as to avoid spurious overflow
// TODO: needed for CABS
ValueWithRealFlags<Real> HYPOT(
const Real &, Rounding rounding = Rounding::TiesToEven) const;
const Real &, Rounding rounding = defaultRounding) const;
template<typename INT> constexpr INT EXPONENT() const {
std::uint64_t exponent{Exponent()};
@ -117,6 +118,13 @@ public:
return epsilon;
}
constexpr Real FlushDenormalToZero() const {
if (IsDenormal()) {
return Real{};
}
return *this;
}
// TODO: Configurable NaN representations
static constexpr Real NaN() {
return {Word{maxExponent}
@ -136,7 +144,7 @@ public:
template<typename INT>
static ValueWithRealFlags<Real> FromInteger(
const INT &n, Rounding rounding = Rounding::TiesToEven) {
const INT &n, Rounding rounding = defaultRounding) {
bool isNegative{n.IsNegative()};
INT absN{n};
if (isNegative) {
@ -224,7 +232,7 @@ public:
template<typename A>
static ValueWithRealFlags<Real> Convert(
const A &x, Rounding rounding = Rounding::TiesToEven) {
const A &x, Rounding rounding = defaultRounding) {
bool isNegative{x.IsNegative()};
A absX{x};
if (isNegative) {
@ -307,7 +315,7 @@ private:
// a maximal exponent and zero fraction doesn't signify infinity, although
// this member function will detect overflow and encode infinities).
RealFlags Normalize(bool negative, std::uint64_t exponent,
const Fraction &fraction, Rounding rounding = Rounding::TiesToEven,
const Fraction &fraction, Rounding rounding = defaultRounding,
RoundingBits *roundingBits = nullptr);
// Rounds a result, if necessary, in place.

View File

@ -41,21 +41,21 @@ std::optional<SubscriptIntegerExpr> Triplet::lower() const {
if (lower_) {
return {**lower_};
}
return {};
return std::nullopt;
}
std::optional<SubscriptIntegerExpr> Triplet::upper() const {
if (upper_) {
return {**upper_};
}
return {};
return std::nullopt;
}
std::optional<SubscriptIntegerExpr> Triplet::stride() const {
if (stride_) {
return {**stride_};
}
return {};
return std::nullopt;
}
CoarrayRef::CoarrayRef(std::vector<const Symbol *> &&c,