121 lines
4 KiB
C
121 lines
4 KiB
C
|
// 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_
|