b7d463f1d5
Original-commit: flang-compiler/f18@e55cc39bad Reviewed-on: https://github.com/flang-compiler/f18/pull/671 Tree-same-pre-rewrite: false
117 lines
4.1 KiB
C++
117 lines
4.1 KiB
C++
// Copyright (c) 2018-2019, 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_DECIMAL_BINARY_FLOATING_POINT_H_
|
|
#define FORTRAN_DECIMAL_BINARY_FLOATING_POINT_H_
|
|
|
|
// Access and manipulate the fields of an IEEE-754 binary
|
|
// floating-point value via a generalized template.
|
|
|
|
#include <cinttypes>
|
|
#include <climits>
|
|
#include <cstring>
|
|
#include <type_traits>
|
|
|
|
namespace Fortran::decimal {
|
|
|
|
template<int BITS> struct HostUnsignedIntTypeHelper {
|
|
using type = std::conditional_t<(BITS <= 8), std::uint8_t,
|
|
std::conditional_t<(BITS <= 16), std::uint16_t,
|
|
std::conditional_t<(BITS <= 32), std::uint32_t,
|
|
std::conditional_t<(BITS <= 64), std::uint64_t, __uint128_t>>>>;
|
|
};
|
|
template<int BITS>
|
|
using HostUnsignedIntType = typename HostUnsignedIntTypeHelper<BITS>::type;
|
|
|
|
static constexpr int BitsForPrecision(int prec) {
|
|
switch (prec) {
|
|
case 8: return 16;
|
|
case 11: return 16;
|
|
case 24: return 32;
|
|
case 53: return 64;
|
|
case 64: return 80;
|
|
case 112: return 128;
|
|
default: return -1;
|
|
}
|
|
}
|
|
|
|
// LOG10(2.)*1E12
|
|
static constexpr std::int64_t ScaledLogBaseTenOfTwo{301029995664};
|
|
|
|
template<int PRECISION> struct BinaryFloatingPointNumber {
|
|
static constexpr int precision{PRECISION};
|
|
static constexpr int bits{BitsForPrecision(precision)};
|
|
using RawType = HostUnsignedIntType<bits>;
|
|
static_assert(CHAR_BIT * sizeof(RawType) >= bits);
|
|
static constexpr bool implicitMSB{precision != 64 /*x87*/};
|
|
static constexpr int significandBits{precision - implicitMSB};
|
|
static constexpr int exponentBits{bits - 1 - significandBits};
|
|
static constexpr int maxExponent{(1 << exponentBits) - 1};
|
|
static constexpr int exponentBias{maxExponent / 2};
|
|
static constexpr RawType significandMask{(RawType{1} << significandBits) - 1};
|
|
static constexpr int RANGE{static_cast<int>(
|
|
(exponentBias - 1) * ScaledLogBaseTenOfTwo / 1000000000000)};
|
|
|
|
BinaryFloatingPointNumber() {} // zero
|
|
BinaryFloatingPointNumber(const BinaryFloatingPointNumber &that) = default;
|
|
BinaryFloatingPointNumber(BinaryFloatingPointNumber &&that) = default;
|
|
BinaryFloatingPointNumber &operator=(
|
|
const BinaryFloatingPointNumber &that) = default;
|
|
BinaryFloatingPointNumber &operator=(
|
|
BinaryFloatingPointNumber &&that) = default;
|
|
|
|
template<typename A> explicit constexpr BinaryFloatingPointNumber(A x) {
|
|
static_assert(sizeof raw <= sizeof x);
|
|
std::memcpy(reinterpret_cast<void *>(&raw),
|
|
reinterpret_cast<const void *>(&x), sizeof raw);
|
|
}
|
|
|
|
constexpr int BiasedExponent() const {
|
|
return static_cast<int>(
|
|
(raw >> significandBits) & ((1 << exponentBits) - 1));
|
|
}
|
|
constexpr int UnbiasedExponent() const {
|
|
int biased{BiasedExponent()};
|
|
return biased - exponentBias + (biased == 0);
|
|
}
|
|
constexpr RawType Significand() const { return raw & significandMask; }
|
|
constexpr RawType Fraction() const {
|
|
RawType sig{Significand()};
|
|
if (implicitMSB && BiasedExponent() > 0) {
|
|
sig |= RawType{1} << significandBits;
|
|
}
|
|
return sig;
|
|
}
|
|
|
|
constexpr bool IsZero() const {
|
|
return (raw & ((RawType{1} << (bits - 1)) - 1)) == 0;
|
|
}
|
|
constexpr bool IsNaN() const {
|
|
return BiasedExponent() == maxExponent && Significand() != 0;
|
|
}
|
|
constexpr bool IsInfinite() const {
|
|
return BiasedExponent() == maxExponent && Significand() == 0;
|
|
}
|
|
constexpr bool IsMaximalFiniteMagnitude() const {
|
|
return BiasedExponent() == maxExponent - 1 &&
|
|
Significand() == significandMask;
|
|
}
|
|
constexpr bool IsNegative() const { return (raw >> (bits - 1)) & 1; }
|
|
|
|
constexpr void Negate() { raw ^= RawType{1} << (bits - 1); }
|
|
|
|
RawType raw{0};
|
|
};
|
|
}
|
|
#endif
|