llvm/flang/lib/evaluate/real.h

121 lines
4 KiB
C
Raw Normal View History

// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FORTRAN_EVALUATE_REAL_H_
#define FORTRAN_EVALUATE_REAL_H_
#include "common.h"
#include "integer.h"
#include <cinttypes>
namespace Fortran::evaluate {
// The class template parameter specifies the total number of bits in the
// significand, including any bit that might be implicit in a machine
// representation.
template<int SIGNIFICAND_BITS> class Real {
public:
static constexpr int significandBits{SIGNIFICAND_BITS};
static_assert(significandBits > 0);
constexpr Real() {} // +0.0
constexpr Real(std::int64_t n)
: significand_{n}, exponent_{64}, negative_{n < 0} {
if (negative_) {
significand_ = significand_.Negate().value; // overflow is safe to ignore
}
Normalize();
}
constexpr bool IsNegative() const { return negative_ && !notANumber_; }
constexpr bool IsFinite() const { return !infinite_ && !notANumber_; }
constexpr bool IsInfinite() const { return infinite_ && !notANumber_; }
constexpr bool IsANumber() const { return !notANumber_; }
constexpr bool IsNotANumber() const { return notANumber_; }
constexpr bool IsZero() const { return !notANumber_ && significand_.IsZero(); }
constexpr Relation Compare(const Real &y) const {
if (notANumber_ || y.notANumber_) {
return Relation::Unordered;
} else if (infinite_) {
if (y.infinite_) {
if (negative_) {
return y.negative_ ? Relation::Equal : Relation::Less;
} else {
return y.negative_ ? Relation::Greater : Relation::Equal;
}
} else {
return negative_ ? Relation::Less : Relation::Greater;
}
} else if (y.infinite_) {
return y.negative_ ? Relation::Greater : Relation::Less;
} else {
// two finite numbers
if (exponent_ == y.exponent_) {
Ordering order{significand_.CompareUnsigned(y.significand_)};
if (order == Ordering::Equal) {
if (negative_ == y.negative_ ||
(exponent_ == 0 && significand_.IsZero())) {
// Ignore signs on zeros, +0.0 == -0.0
return Relation::Equal;
} else {
// finite nonzero numbers, same exponent & significand
return negative_ ? Relation::Less : Relation::Greater;
}
} else {
// finite numbers, same exponent, distinct significands
if (negative_ != y.negative_) {
return negative_ ? Relation::Less : Relation::Greater;
} else {
return RelationFromOrdering(order);
}
}
} else {
// not same exponent
if (negative_ != y.negative_) {
return negative_ ? Relation::Less : Relation::Greater;
} else {
return exponent_ < y.exponent_ ? Relation::Less : Relation::Greater;
}
}
}
}
private:
using Significand = Integer<significandBits>;
using DoubleSignificand = Integer<2 * significandBits>;
// All values are normalized on output and assumed normal on input.
void Normalize() {
if (!notANumber_ && !infinite_) {
int shift{significand_.LEADZ()};
if (shift >= significandBits) {
exponent_ = 0; // +/-0.0
} else {
exponent_ -= shift;
significand_ = significand_.SHIFTL(shift);
}
}
}
Significand significand_{};
int exponent_{0}; // unbiased; 1.0 has exponent 1
bool negative_{false};
bool infinite_{false};
bool notANumber_{false};
};
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_REAL_H_