//===-- include/flang/Decimal/binary-floating-point.h -----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #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 "flang/Common/real.h" #include "flang/Common/uint128.h" #include #include #include #include namespace Fortran::decimal { template class BinaryFloatingPointNumber : public common::RealDetails { public: using Details = common::RealDetails; using Details::bits; using Details::decimalPrecision; using Details::decimalRange; using Details::exponentBias; using Details::exponentBits; using Details::isImplicitMSB; using Details::maxDecimalConversionDigits; using Details::maxExponent; using Details::significandBits; using RawType = common::HostUnsignedIntType; static_assert(CHAR_BIT * sizeof(RawType) >= bits); static constexpr RawType significandMask{(RawType{1} << significandBits) - 1}; constexpr BinaryFloatingPointNumber() {} // zero constexpr BinaryFloatingPointNumber( const BinaryFloatingPointNumber &that) = default; constexpr BinaryFloatingPointNumber( BinaryFloatingPointNumber &&that) = default; constexpr BinaryFloatingPointNumber &operator=( const BinaryFloatingPointNumber &that) = default; constexpr BinaryFloatingPointNumber &operator=( BinaryFloatingPointNumber &&that) = default; constexpr explicit BinaryFloatingPointNumber(RawType raw) : raw_{raw} {} RawType raw() const { return raw_; } template explicit constexpr BinaryFloatingPointNumber(A x) { static_assert(sizeof raw_ <= sizeof x); std::memcpy(reinterpret_cast(&raw_), reinterpret_cast(&x), sizeof raw_); } constexpr int BiasedExponent() const { return static_cast( (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 (isImplicitMSB && 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) != 0; } constexpr void Negate() { raw_ ^= RawType{1} << (bits - 1); } // For calculating the nearest neighbors of a floating-point value constexpr void Previous() { RemoveExplicitMSB(); --raw_; InsertExplicitMSB(); } constexpr void Next() { RemoveExplicitMSB(); ++raw_; InsertExplicitMSB(); } private: constexpr void RemoveExplicitMSB() { if constexpr (!isImplicitMSB) { raw_ = (raw_ & (significandMask >> 1)) | ((raw_ & ~significandMask) >> 1); } } constexpr void InsertExplicitMSB() { if constexpr (!isImplicitMSB) { constexpr RawType mask{significandMask >> 1}; raw_ = (raw_ & mask) | ((raw_ & ~mask) << 1); if (BiasedExponent() > 0) { raw_ |= RawType{1} << (significandBits - 1); } } } RawType raw_{0}; }; } // namespace Fortran::decimal #endif