2018-06-02 00:30:31 +02:00
|
|
|
// 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"
|
2018-06-13 19:34:23 +02:00
|
|
|
#include "rounding-bits.h"
|
2018-06-02 00:30:31 +02:00
|
|
|
#include <cinttypes>
|
2018-06-04 18:49:47 +02:00
|
|
|
#include <limits>
|
2018-11-08 18:32:28 +01:00
|
|
|
#include <ostream>
|
2018-06-21 00:10:34 +02:00
|
|
|
#include <string>
|
2018-06-02 00:30:31 +02:00
|
|
|
|
2018-10-10 23:29:35 +02:00
|
|
|
// Some environments, viz. clang on Darwin, allow the macro HUGE
|
|
|
|
// to leak out of <math.h> even when it is never directly included.
|
|
|
|
#undef HUGE
|
|
|
|
|
2018-06-12 21:59:31 +02:00
|
|
|
namespace Fortran::evaluate::value {
|
2018-06-02 00:30:31 +02:00
|
|
|
|
2018-06-13 19:34:23 +02:00
|
|
|
// Models IEEE binary floating-point numbers (IEEE 754-2008,
|
|
|
|
// ISO/IEC/IEEE 60559.2011). The first argument to this
|
|
|
|
// class template must be (or look like) an instance of Integer<>;
|
|
|
|
// the second specifies the number of effective bits in the fraction;
|
|
|
|
// the third, if true, indicates that the most significant position of the
|
|
|
|
// fraction is an implicit bit whose value is assumed to be 1 in a finite
|
|
|
|
// normal number.
|
2018-06-05 22:55:56 +02:00
|
|
|
template<typename WORD, int PRECISION, bool IMPLICIT_MSB = true> class Real {
|
2018-06-02 00:30:31 +02:00
|
|
|
public:
|
2018-06-05 22:55:56 +02:00
|
|
|
using Word = WORD;
|
|
|
|
static constexpr int bits{Word::bits};
|
2018-06-05 00:56:40 +02:00
|
|
|
static constexpr int precision{PRECISION};
|
2018-06-05 22:55:56 +02:00
|
|
|
static constexpr bool implicitMSB{IMPLICIT_MSB};
|
|
|
|
static constexpr int significandBits{precision - implicitMSB};
|
|
|
|
static constexpr int exponentBits{bits - significandBits - 1 /*sign*/};
|
2018-06-05 00:56:40 +02:00
|
|
|
static_assert(precision > 0);
|
2018-06-05 22:55:56 +02:00
|
|
|
static_assert(exponentBits > 1);
|
|
|
|
static constexpr std::uint64_t maxExponent{(1 << exponentBits) - 1};
|
|
|
|
static constexpr std::uint64_t exponentBias{maxExponent / 2};
|
2018-06-02 00:30:31 +02:00
|
|
|
|
2018-11-08 18:32:28 +01:00
|
|
|
// Decimal precision
|
|
|
|
// log(2)/log(10) = 0.30102999... in any base; avoid floating constexpr
|
|
|
|
static constexpr int decimalDigits{(precision * 30103) / 100000};
|
|
|
|
|
|
|
|
// Associates a decimal exponent with an integral value for formmatting.
|
|
|
|
struct ScaledDecimal {
|
|
|
|
bool negative{false};
|
|
|
|
Word integer;
|
|
|
|
int decimalExponent{0}; // Exxx
|
|
|
|
};
|
|
|
|
|
2018-07-24 21:58:29 +02:00
|
|
|
template<typename W, int P, bool I> friend class Real;
|
|
|
|
|
2018-06-02 00:30:31 +02:00
|
|
|
constexpr Real() {} // +0.0
|
2018-06-04 18:49:47 +02:00
|
|
|
constexpr Real(const Real &) = default;
|
2018-06-06 01:29:26 +02:00
|
|
|
constexpr Real(const Word &bits) : word_{bits} {}
|
2018-06-06 20:48:00 +02:00
|
|
|
constexpr Real &operator=(const Real &) = default;
|
2018-07-26 00:02:21 +02:00
|
|
|
constexpr Real &operator=(Real &&) = default;
|
2018-06-02 00:30:31 +02:00
|
|
|
|
2018-11-08 18:32:28 +01:00
|
|
|
// TODO ANINT, CEILING, FLOOR, DIM, MAX, MIN, DPROD, FRACTION
|
2018-06-05 01:22:58 +02:00
|
|
|
// HUGE, INT/NINT, MAXEXPONENT, MINEXPONENT, NEAREST, OUT_OF_RANGE,
|
|
|
|
// PRECISION, HUGE, TINY, RRSPACING/SPACING, SCALE, SET_EXPONENT, SIGN
|
|
|
|
|
2018-06-06 01:29:26 +02:00
|
|
|
constexpr bool IsNegative() const {
|
|
|
|
return !IsNotANumber() && word_.BTEST(bits - 1);
|
|
|
|
}
|
2018-06-05 22:55:56 +02:00
|
|
|
constexpr bool IsNotANumber() const {
|
|
|
|
return Exponent() == maxExponent && !GetSignificand().IsZero();
|
|
|
|
}
|
2018-06-09 00:49:06 +02:00
|
|
|
constexpr bool IsQuietNaN() const {
|
|
|
|
return Exponent() == maxExponent &&
|
|
|
|
GetSignificand().BTEST(significandBits - 1);
|
|
|
|
}
|
|
|
|
constexpr bool IsSignalingNaN() const {
|
|
|
|
return IsNotANumber() && !GetSignificand().BTEST(significandBits - 1);
|
|
|
|
}
|
2018-06-05 22:55:56 +02:00
|
|
|
constexpr bool IsInfinite() const {
|
|
|
|
return Exponent() == maxExponent && GetSignificand().IsZero();
|
|
|
|
}
|
2018-06-05 01:22:58 +02:00
|
|
|
constexpr bool IsZero() const {
|
2018-06-05 22:55:56 +02:00
|
|
|
return Exponent() == 0 && GetSignificand().IsZero();
|
|
|
|
}
|
2018-06-08 19:24:15 +02:00
|
|
|
constexpr bool IsDenormal() const {
|
|
|
|
return Exponent() == 0 && !GetSignificand().IsZero();
|
|
|
|
}
|
2018-06-05 22:55:56 +02:00
|
|
|
|
|
|
|
constexpr Real ABS() const { // non-arithmetic, no flags returned
|
2018-06-14 22:43:02 +02:00
|
|
|
return {word_.IBCLR(bits - 1)};
|
2018-06-05 01:22:58 +02:00
|
|
|
}
|
2018-06-02 00:30:31 +02:00
|
|
|
|
2018-06-18 20:03:43 +02:00
|
|
|
constexpr Real Negate() const { return {word_.IEOR(word_.MASKL(1))}; }
|
2018-06-05 00:56:40 +02:00
|
|
|
|
2018-06-13 19:34:23 +02:00
|
|
|
Relation Compare(const Real &) const;
|
|
|
|
ValueWithRealFlags<Real> Add(
|
2018-07-26 00:02:21 +02:00
|
|
|
const Real &, Rounding rounding = defaultRounding) const;
|
2018-06-13 19:34:23 +02:00
|
|
|
ValueWithRealFlags<Real> Subtract(
|
2018-07-26 00:02:21 +02:00
|
|
|
const Real &y, Rounding rounding = defaultRounding) const {
|
2018-06-13 19:34:23 +02:00
|
|
|
return Add(y.Negate(), rounding);
|
|
|
|
}
|
|
|
|
ValueWithRealFlags<Real> Multiply(
|
2018-07-26 00:02:21 +02:00
|
|
|
const Real &, Rounding rounding = defaultRounding) const;
|
2018-06-13 19:34:23 +02:00
|
|
|
ValueWithRealFlags<Real> Divide(
|
2018-07-26 00:02:21 +02:00
|
|
|
const Real &, Rounding rounding = defaultRounding) const;
|
2018-06-13 19:34:23 +02:00
|
|
|
|
2018-06-14 01:08:12 +02:00
|
|
|
// SQRT(x**2 + y**2) but computed so as to avoid spurious overflow
|
|
|
|
// TODO: needed for CABS
|
|
|
|
ValueWithRealFlags<Real> HYPOT(
|
2018-07-26 00:02:21 +02:00
|
|
|
const Real &, Rounding rounding = defaultRounding) const;
|
2018-06-14 01:08:12 +02:00
|
|
|
|
2018-06-12 22:33:08 +02:00
|
|
|
template<typename INT> constexpr INT EXPONENT() const {
|
2018-06-05 22:55:56 +02:00
|
|
|
std::uint64_t exponent{Exponent()};
|
|
|
|
if (exponent == maxExponent) {
|
2018-06-12 21:59:31 +02:00
|
|
|
return INT::HUGE();
|
2018-06-05 00:56:40 +02:00
|
|
|
} else {
|
2018-06-05 22:55:56 +02:00
|
|
|
return {static_cast<std::int64_t>(exponent - exponentBias)};
|
2018-06-05 00:56:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr Real EPSILON() {
|
|
|
|
Real epsilon;
|
2018-06-05 22:55:56 +02:00
|
|
|
epsilon.Normalize(false, exponentBias - precision, Fraction::MASKL(1));
|
2018-06-05 00:56:40 +02:00
|
|
|
return epsilon;
|
|
|
|
}
|
|
|
|
|
2018-07-26 00:02:21 +02:00
|
|
|
constexpr Real FlushDenormalToZero() const {
|
|
|
|
if (IsDenormal()) {
|
|
|
|
return Real{};
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-08-04 01:02:05 +02:00
|
|
|
// TODO: Configurable NotANumber representations
|
|
|
|
static constexpr Real NotANumber() {
|
2018-07-25 22:46:13 +02:00
|
|
|
return {Word{maxExponent}
|
|
|
|
.SHIFTL(significandBits)
|
|
|
|
.IBSET(significandBits - 1)
|
|
|
|
.IBSET(significandBits - 2)};
|
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr Real Infinity(bool negative) {
|
|
|
|
Word infinity{maxExponent};
|
|
|
|
infinity = infinity.SHIFTL(significandBits);
|
|
|
|
if (negative) {
|
|
|
|
infinity = infinity.IBSET(infinity.bits - 1);
|
|
|
|
}
|
|
|
|
return {infinity};
|
|
|
|
}
|
|
|
|
|
2018-06-13 19:34:23 +02:00
|
|
|
template<typename INT>
|
2018-06-14 01:08:12 +02:00
|
|
|
static ValueWithRealFlags<Real> FromInteger(
|
2018-07-26 00:02:21 +02:00
|
|
|
const INT &n, Rounding rounding = defaultRounding) {
|
2018-06-13 19:34:23 +02:00
|
|
|
bool isNegative{n.IsNegative()};
|
|
|
|
INT absN{n};
|
|
|
|
if (isNegative) {
|
|
|
|
absN = n.Negate().value; // overflow is safe to ignore
|
|
|
|
}
|
|
|
|
int leadz{absN.LEADZ()};
|
|
|
|
if (leadz >= absN.bits) {
|
|
|
|
return {}; // all bits zero -> +0.0
|
|
|
|
}
|
|
|
|
ValueWithRealFlags<Real> result;
|
|
|
|
std::uint64_t exponent{exponentBias + absN.bits - leadz - 1};
|
|
|
|
int bitsNeeded{absN.bits - (leadz + implicitMSB)};
|
|
|
|
int bitsLost{bitsNeeded - significandBits};
|
|
|
|
if (bitsLost <= 0) {
|
|
|
|
Fraction fraction{Fraction::ConvertUnsigned(absN).value};
|
|
|
|
result.flags |= result.value.Normalize(
|
|
|
|
isNegative, exponent, fraction.SHIFTL(-bitsLost));
|
|
|
|
} else {
|
|
|
|
Fraction fraction{Fraction::ConvertUnsigned(absN.SHIFTR(bitsLost)).value};
|
|
|
|
result.flags |= result.value.Normalize(isNegative, exponent, fraction);
|
|
|
|
RoundingBits roundingBits{absN, bitsLost};
|
|
|
|
result.flags |= result.value.Round(rounding, roundingBits);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-11-08 18:32:28 +01:00
|
|
|
// Truncation to integer in same real format.
|
|
|
|
constexpr ValueWithRealFlags<Real> AINT() const {
|
|
|
|
ValueWithRealFlags<Real> result{*this};
|
|
|
|
if (IsNotANumber()) {
|
|
|
|
result.flags.set(RealFlag::InvalidArgument);
|
|
|
|
result.value = NotANumber();
|
|
|
|
} else if (IsInfinite()) {
|
|
|
|
result.flags.set(RealFlag::Overflow);
|
|
|
|
} else {
|
|
|
|
std::uint64_t exponent{Exponent()};
|
|
|
|
if (exponent < exponentBias) { // |x| < 1.0
|
|
|
|
result.value.Normalize(IsNegative(), 0, Fraction{}); // +/-0.0
|
|
|
|
} else {
|
|
|
|
constexpr std::uint64_t noClipExponent{exponentBias + precision - 1};
|
|
|
|
if (int clip = noClipExponent - exponent; clip > 0) {
|
|
|
|
result.value.word_ = result.value.word_.IAND(Word::MASKR(clip).NOT());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-06-05 01:22:58 +02:00
|
|
|
template<typename INT> constexpr ValueWithRealFlags<INT> ToInteger() const {
|
2018-06-06 20:26:00 +02:00
|
|
|
ValueWithRealFlags<INT> result;
|
2018-11-08 18:32:28 +01:00
|
|
|
if (IsNotANumber()) {
|
2018-06-06 20:11:35 +02:00
|
|
|
result.flags.set(RealFlag::InvalidArgument);
|
2018-06-05 00:56:40 +02:00
|
|
|
result.value = result.value.HUGE();
|
2018-11-08 18:32:28 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
bool isNegative{IsNegative()};
|
|
|
|
std::uint64_t exponent{Exponent()};
|
|
|
|
Fraction fraction{GetFraction()};
|
|
|
|
if (exponent >= maxExponent || // +/-Inf
|
2018-06-06 20:48:00 +02:00
|
|
|
exponent >= exponentBias + result.value.bits) { // too big
|
2018-06-05 22:55:56 +02:00
|
|
|
if (isNegative) {
|
2018-11-08 18:32:28 +01:00
|
|
|
result.value = result.value.MASKL(1); // most negative integer value
|
2018-06-05 00:56:40 +02:00
|
|
|
} else {
|
2018-11-08 18:32:28 +01:00
|
|
|
result.value = result.value.HUGE(); // most positive integer value
|
2018-06-05 00:56:40 +02:00
|
|
|
}
|
2018-06-06 20:11:35 +02:00
|
|
|
result.flags.set(RealFlag::Overflow);
|
2018-06-06 20:26:00 +02:00
|
|
|
} else if (exponent < exponentBias) { // |x| < 1.0 -> 0
|
2018-06-05 22:55:56 +02:00
|
|
|
if (!fraction.IsZero()) {
|
2018-06-06 20:11:35 +02:00
|
|
|
result.flags.set(RealFlag::Underflow);
|
|
|
|
result.flags.set(RealFlag::Inexact);
|
2018-06-05 22:55:56 +02:00
|
|
|
}
|
2018-06-05 00:56:40 +02:00
|
|
|
} else {
|
2018-06-06 20:26:00 +02:00
|
|
|
// finite number |x| >= 1.0
|
|
|
|
constexpr std::uint64_t noShiftExponent{exponentBias + precision - 1};
|
|
|
|
if (exponent < noShiftExponent) {
|
|
|
|
int rshift = noShiftExponent - exponent;
|
2018-06-05 22:55:56 +02:00
|
|
|
if (!fraction.IBITS(0, rshift).IsZero()) {
|
2018-06-06 20:11:35 +02:00
|
|
|
result.flags.set(RealFlag::Inexact);
|
2018-06-05 22:55:56 +02:00
|
|
|
}
|
2018-07-11 02:11:12 +02:00
|
|
|
auto truncated{result.value.ConvertUnsigned(fraction.SHIFTR(rshift))};
|
2018-06-05 22:55:56 +02:00
|
|
|
if (truncated.overflow) {
|
2018-06-06 20:11:35 +02:00
|
|
|
result.flags.set(RealFlag::Overflow);
|
2018-06-05 22:55:56 +02:00
|
|
|
} else {
|
|
|
|
result.value = truncated.value;
|
|
|
|
}
|
|
|
|
} else {
|
2018-06-06 20:26:00 +02:00
|
|
|
int lshift = exponent - noShiftExponent;
|
2018-06-05 22:55:56 +02:00
|
|
|
if (lshift + precision >= result.value.bits) {
|
2018-06-06 20:11:35 +02:00
|
|
|
result.flags.set(RealFlag::Overflow);
|
2018-06-05 22:55:56 +02:00
|
|
|
} else {
|
2018-06-12 22:33:08 +02:00
|
|
|
result.value =
|
|
|
|
result.value.ConvertUnsigned(fraction).value.SHIFTL(lshift);
|
2018-06-05 22:55:56 +02:00
|
|
|
}
|
2018-06-05 00:56:40 +02:00
|
|
|
}
|
2018-06-06 20:11:35 +02:00
|
|
|
if (result.flags.test(RealFlag::Overflow)) {
|
2018-06-05 22:55:56 +02:00
|
|
|
result.value = result.value.HUGE();
|
|
|
|
} else if (isNegative) {
|
2018-07-11 02:11:12 +02:00
|
|
|
auto negated{result.value.Negate()};
|
2018-06-06 01:29:26 +02:00
|
|
|
if (negated.overflow) {
|
2018-06-06 20:11:35 +02:00
|
|
|
result.flags.set(RealFlag::Overflow);
|
2018-06-05 00:56:40 +02:00
|
|
|
result.value = result.value.HUGE();
|
|
|
|
} else {
|
|
|
|
result.value = negated.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2018-06-04 18:49:47 +02:00
|
|
|
|
2018-07-24 21:58:29 +02:00
|
|
|
template<typename A>
|
|
|
|
static ValueWithRealFlags<Real> Convert(
|
2018-07-26 00:02:21 +02:00
|
|
|
const A &x, Rounding rounding = defaultRounding) {
|
2018-07-24 21:58:29 +02:00
|
|
|
bool isNegative{x.IsNegative()};
|
|
|
|
A absX{x};
|
|
|
|
if (isNegative) {
|
|
|
|
absX = x.Negate();
|
|
|
|
}
|
|
|
|
ValueWithRealFlags<Real> result;
|
|
|
|
std::uint64_t exponent{exponentBias + x.Exponent() - A::exponentBias};
|
|
|
|
int bitsLost{A::precision - precision};
|
|
|
|
typename A::Fraction xFraction{x.GetFraction()};
|
|
|
|
if (bitsLost <= 0) {
|
|
|
|
Fraction fraction{Fraction::ConvertUnsigned(xFraction).value};
|
|
|
|
result.flags |= result.value.Normalize(isNegative, exponent, fraction);
|
|
|
|
} else {
|
|
|
|
Fraction fraction{
|
|
|
|
Fraction::ConvertUnsigned(xFraction.SHIFTR(bitsLost)).value};
|
|
|
|
result.flags |= result.value.Normalize(isNegative, exponent, fraction);
|
|
|
|
RoundingBits roundingBits{xFraction, bitsLost};
|
|
|
|
result.flags |= result.value.Round(rounding, roundingBits);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-11-08 18:32:28 +01:00
|
|
|
// Represents the number as "J*(10**K)" where J and K are integers.
|
|
|
|
ValueWithRealFlags<ScaledDecimal> AsScaledDecimal() const;
|
|
|
|
|
2018-06-13 19:34:23 +02:00
|
|
|
constexpr Word RawBits() const { return word_; }
|
2018-06-05 00:56:40 +02:00
|
|
|
|
2018-11-08 18:32:28 +01:00
|
|
|
// Extracts "raw" biased exponent field.
|
2018-06-13 19:34:23 +02:00
|
|
|
constexpr std::uint64_t Exponent() const {
|
|
|
|
return word_.IBITS(significandBits, exponentBits).ToUInt64();
|
2018-06-04 18:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-08-09 01:30:58 +02:00
|
|
|
static ValueWithRealFlags<Real> Read(
|
|
|
|
const char *&, Rounding rounding = defaultRounding);
|
2018-06-21 00:10:34 +02:00
|
|
|
std::string DumpHexadecimal() const;
|
|
|
|
|
2018-11-08 18:32:28 +01:00
|
|
|
// Emits a character representation for an equivalent Fortran constant
|
|
|
|
// or parenthesized constant expression that produces this value.
|
|
|
|
std::ostream &AsFortran(std::ostream &, int kind) const;
|
|
|
|
|
2018-06-02 00:30:31 +02:00
|
|
|
private:
|
2018-06-05 22:55:56 +02:00
|
|
|
using Fraction = Integer<precision>; // all bits made explicit
|
|
|
|
using Significand = Integer<significandBits>; // no implicit bit
|
2018-06-04 18:49:47 +02:00
|
|
|
|
2018-06-05 22:55:56 +02:00
|
|
|
constexpr Significand GetSignificand() const {
|
2018-06-12 21:59:31 +02:00
|
|
|
return Significand::ConvertUnsigned(word_).value;
|
2018-06-05 22:55:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
constexpr Fraction GetFraction() const {
|
2018-06-12 21:59:31 +02:00
|
|
|
Fraction result{Fraction::ConvertUnsigned(word_).value};
|
2018-06-05 22:55:56 +02:00
|
|
|
if constexpr (!implicitMSB) {
|
|
|
|
return result;
|
2018-06-04 18:49:47 +02:00
|
|
|
} else {
|
2018-06-05 22:55:56 +02:00
|
|
|
std::uint64_t exponent{Exponent()};
|
|
|
|
if (exponent > 0 && exponent < maxExponent) {
|
|
|
|
return result.IBSET(significandBits);
|
|
|
|
} else {
|
|
|
|
return result.IBCLR(significandBits);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-12 01:01:54 +02:00
|
|
|
constexpr std::int64_t CombineExponents(const Real &y, bool forDivide) const {
|
|
|
|
std::int64_t exponent = Exponent(), yExponent = y.Exponent();
|
|
|
|
// A zero exponent field value has the same weight as 1.
|
|
|
|
exponent += !exponent;
|
|
|
|
yExponent += !yExponent;
|
|
|
|
if (forDivide) {
|
|
|
|
exponent += exponentBias - yExponent;
|
|
|
|
} else {
|
|
|
|
exponent += yExponent - exponentBias + 1;
|
|
|
|
}
|
|
|
|
return exponent;
|
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr bool NextQuotientBit(
|
|
|
|
Fraction &top, bool &msb, const Fraction &divisor) {
|
|
|
|
bool greaterOrEqual{msb || top.CompareUnsigned(divisor) != Ordering::Less};
|
|
|
|
if (greaterOrEqual) {
|
|
|
|
top = top.SubtractSigned(divisor).value;
|
|
|
|
}
|
|
|
|
auto doubled{top.AddUnsigned(top)};
|
|
|
|
top = doubled.value;
|
|
|
|
msb = doubled.carry;
|
|
|
|
return greaterOrEqual;
|
|
|
|
}
|
|
|
|
|
2018-06-14 01:08:12 +02:00
|
|
|
// Normalizes and marshals the fields of a floating-point number in place.
|
2018-08-04 01:02:05 +02:00
|
|
|
// The value is a number, and a zero fraction means a zero value (i.e.,
|
2018-06-14 01:08:12 +02:00
|
|
|
// a maximal exponent and zero fraction doesn't signify infinity, although
|
|
|
|
// this member function will detect overflow and encode infinities).
|
2018-06-13 19:34:23 +02:00
|
|
|
RealFlags Normalize(bool negative, std::uint64_t exponent,
|
2018-07-26 00:02:21 +02:00
|
|
|
const Fraction &fraction, Rounding rounding = defaultRounding,
|
2018-06-13 19:34:23 +02:00
|
|
|
RoundingBits *roundingBits = nullptr);
|
2018-06-04 18:49:47 +02:00
|
|
|
|
2018-06-13 19:34:23 +02:00
|
|
|
// Rounds a result, if necessary, in place.
|
2018-06-14 01:08:12 +02:00
|
|
|
RealFlags Round(Rounding, const RoundingBits &, bool multiply = false);
|
2018-06-02 00:30:31 +02:00
|
|
|
|
2018-06-13 19:34:23 +02:00
|
|
|
static void NormalizeAndRound(ValueWithRealFlags<Real> &result,
|
|
|
|
bool isNegative, std::uint64_t exponent, const Fraction &, Rounding,
|
2018-06-14 01:08:12 +02:00
|
|
|
RoundingBits, bool multiply = false);
|
2018-06-12 01:01:54 +02:00
|
|
|
|
2018-06-05 22:55:56 +02:00
|
|
|
Word word_{}; // an Integer<>
|
2018-06-02 00:30:31 +02:00
|
|
|
};
|
|
|
|
|
2018-06-05 22:55:56 +02:00
|
|
|
extern template class Real<Integer<16>, 11>;
|
|
|
|
extern template class Real<Integer<32>, 24>;
|
|
|
|
extern template class Real<Integer<64>, 53>;
|
2018-06-12 22:33:08 +02:00
|
|
|
extern template class Real<Integer<80>, 64, false>; // 80387 extended precision
|
2018-06-05 22:55:56 +02:00
|
|
|
extern template class Real<Integer<128>, 112>;
|
2018-06-06 01:55:31 +02:00
|
|
|
// N.B. No "double-double" support.
|
2018-10-25 14:55:23 +02:00
|
|
|
}
|
2018-06-02 00:30:31 +02:00
|
|
|
#endif // FORTRAN_EVALUATE_REAL_H_
|