Loading...
Searching...
No Matches
BitFloat.h
Go to the documentation of this file.
#ifndef SISCO_BIT_FLOAT_H_
#define SISCO_BIT_FLOAT_H_
#include <bit>
#include <cinttypes>
#include <limits>
#include <optional>
#include <stdexcept>
#include <string_view>
namespace casacore {
enum class BitFloatKind : uint8_t {
Zero,
NegativeZero,
Normal,
NaN,
SignallingNaN,
Infinity,
NegativeInfinity,
Subnormal
};
constexpr std::string_view ToString(BitFloatKind kind) {
switch (kind) {
case BitFloatKind::Zero:
return "zero";
case BitFloatKind::NegativeZero:
return "negative zero";
case BitFloatKind::Normal:
return "normal";
case BitFloatKind::NaN:
return "nan";
case BitFloatKind::SignallingNaN:
return "signalling nan";
case BitFloatKind::Infinity:
return "infinity";
case BitFloatKind::NegativeInfinity:
return "negative infinity";
case BitFloatKind::Subnormal:
return "subnormal";
}
__builtin_unreachable();
}
class BitFloat {
public:
constexpr BitFloat() : mantissa_(0), exponent_(-127), sign_(false) {}
constexpr explicit BitFloat(float f)
: mantissa_((std::bit_cast<uint32_t>(f) & 0x007FFFFF) | 0x00800000),
exponent_(static_cast<int8_t>(
(std::bit_cast<uint32_t>(f) & 0x7F800000) >> 23) -
127),
sign_(std::bit_cast<uint32_t>(f) & 0x80000000) {
if (f == 0.0f) mantissa_ = 0;
}
constexpr BitFloat(uint32_t mantissa, int8_t exponent, bool sign)
: mantissa_(mantissa), exponent_(exponent), sign_(sign) {}
constexpr uint32_t Mantissa() const { return mantissa_; }
constexpr int8_t Exponent() const { return exponent_; }
constexpr uint32_t PackMantissa() const {
if (MantissaOverflow()) {
throw std::overflow_error(
"An overflow occured! Value = " + std::to_string(ToFloat()) +
", exponent = " + std::to_string(exponent_) + ", mantissa = " +
std::to_string(mantissa_) + ", sign = " + std::to_string(sign_));
}
return (mantissa_ & 0x7FFFFFFFu) | (sign_ ? 0x80000000u : 0u);
}
constexpr static std::pair<uint32_t, bool> UnpackMantissa(
uint32_t mantissa_with_sign) {
const uint32_t mantissa = (mantissa_with_sign & 0x7FFFFFFFu);
const bool sign = (mantissa_with_sign & 0x80000000u) != 0u;
return {mantissa, sign};
}
constexpr static BitFloat FromCompressed(uint32_t mantissa_with_sign,
int8_t exponent) {
const std::pair<uint32_t, bool> unpacked =
UnpackMantissa(mantissa_with_sign);
return BitFloat(unpacked.first, exponent, unpacked.second);
}
constexpr bool Sign() const { return sign_; }
constexpr BitFloat& operator+=(const BitFloat& rhs) {
if (sign_ == rhs.sign_) {
mantissa_ = mantissa_ + rhs.mantissa_;
} else if (mantissa_ >= rhs.mantissa_) {
mantissa_ = mantissa_ - rhs.mantissa_;
} else {
mantissa_ = rhs.mantissa_ - mantissa_;
sign_ = !sign_;
}
return *this;
}
constexpr BitFloat& operator-=(const BitFloat& rhs) {
if (sign_ != rhs.sign_) {
mantissa_ = mantissa_ + rhs.mantissa_;
} else if (mantissa_ >= rhs.mantissa_) {
mantissa_ = mantissa_ - rhs.mantissa_;
} else {
mantissa_ = rhs.mantissa_ - mantissa_;
sign_ = !sign_;
}
return *this;
}
constexpr BitFloat& operator*=(unsigned factor) {
mantissa_ *= factor;
return *this;
}
constexpr BitFloat& operator/=(unsigned factor) {
mantissa_ /= factor;
return *this;
}
constexpr float ToFloat() const {
int8_t exponent = exponent_;
uint32_t result = mantissa_;
// Exponent values of +128 and -127 have special meaning.
// 128 will be wrapped.
if (exponent_ != static_cast<int8_t>(128u) && exponent_ != -127) {
if (mantissa_ == 0) return sign_ ? -0.0f : 0.0f;
while (result & 0xFF000000) {
++exponent;
result = (result >> 1);
}
while ((result & 0x00800000) == 0) {
--exponent;
result = (result << 1);
}
}
// The double cast of the exponent is necessary to prevent sign extension.
result =
(result & 0x007FFFFF) |
(static_cast<uint32_t>(static_cast<uint8_t>(exponent + 127)) << 23) |
(sign_ ? 0x80000000 : 0x0);
return std::bit_cast<float>(result);
}
explicit constexpr operator float() const { return ToFloat(); }
static constexpr bool AllowsMath(int8_t exponent) {
return exponent != static_cast<int8_t>(128u) && exponent != -127;
}
constexpr bool AllowsMath() const { return AllowsMath(exponent_); }
friend constexpr BitFloat operator-(const BitFloat& input) {
return BitFloat(input.mantissa_, input.exponent_, !input.sign_);
}
friend constexpr bool operator==(const BitFloat& lhs, const BitFloat& rhs) {
return lhs.mantissa_ == rhs.mantissa_ && lhs.exponent_ == rhs.exponent_ &&
lhs.sign_ == rhs.sign_;
}
friend constexpr std::optional<BitFloat> Match(const BitFloat& input,
int8_t value_exponent) {
if (input.Exponent() == value_exponent) {
return input;
} else if (input.Exponent() > value_exponent) {
const uint8_t shift = input.Exponent() - value_exponent;
if (shift > 7)
return {};
else
return BitFloat(input.Mantissa() << shift, value_exponent,
input.Sign());
} else {
const uint8_t shift = value_exponent - input.Exponent();
if (shift > 24)
return BitFloat(0, value_exponent, input.Sign());
else
return BitFloat(input.Mantissa() >> shift, value_exponent,
input.Sign());
}
}
constexpr bool MantissaOverflow() const { return mantissa_ & 0x80000000; }
constexpr static BitFloatKind GetKind(float f) {
const uint32_t value = std::bit_cast<uint32_t>(f);
if (value == 0) {
return BitFloatKind::Zero;
} else if (value == 0x80000000) {
return BitFloatKind::NegativeZero;
} else if ((value & 0x7F800000) == 0x7F800000) {
// exponent is 128
if (value & 0x00400000)
return BitFloatKind::NaN;
else
return BitFloatKind::SignallingNaN;
} else if ((value & 0x7FFFFFFF) == 0b1111111100000000000000000000000) {
if (value & 0x80000000)
return BitFloatKind::NegativeInfinity;
else
return BitFloatKind::Infinity;
} else if ((value & 0x7F800000) == 0) {
return BitFloatKind::Subnormal;
} else {
return BitFloatKind::Normal;
}
}
private:
uint32_t mantissa_;
int8_t exponent_;
bool sign_;
};
} // namespace casacore
#endif
casacore::BitFloat::FromCompressed
static constexpr BitFloat FromCompressed(uint32_t mantissa_with_sign, int8_t exponent)
Constructs a BitFloat from a 'packed mantissa' (see PackMantissa()) and the exponent.
Definition BitFloat.h:115
casacore::BitFloat::operator-=
constexpr BitFloat & operator-=(const BitFloat &rhs)
Like operator+=, but subtracts rhs.
Definition BitFloat.h:144
casacore::BitFloat::Sign
constexpr bool Sign() const
Definition BitFloat.h:122
casacore::BitFloat::MantissaOverflow
constexpr bool MantissaOverflow() const
Returns true if bit 32 is set.
Definition BitFloat.h:267
casacore::BitFloat::PackMantissa
constexpr uint32_t PackMantissa() const
Combines the sign and the mantissa into one uint32_t.
Definition BitFloat.h:89
casacore::BitFloat::BitFloat
constexpr BitFloat()
Constructs a zero-value BitFloat.
Definition BitFloat.h:57
casacore::BitFloat::operator==
friend constexpr bool operator==(const BitFloat &lhs, const BitFloat &rhs)
Definition BitFloat.h:229
casacore::BitFloat::exponent_
int8_t exponent_
Definition BitFloat.h:297
casacore::BitFloat::UnpackMantissa
static constexpr std::pair< uint32_t, bool > UnpackMantissa(uint32_t mantissa_with_sign)
Given a result from PackMantissa(), this function reversed the packing.
Definition BitFloat.h:103
casacore::BitFloat::operator*=
constexpr BitFloat & operator*=(unsigned factor)
Multiplies the value by an integer factor.
Definition BitFloat.h:160
casacore::BitFloat::GetKind
static constexpr BitFloatKind GetKind(float f)
Determine what kind of float the specified value is: normal, nan, inf, etc.
Definition BitFloat.h:271
casacore::BitFloat::BitFloat
constexpr BitFloat(uint32_t mantissa, int8_t exponent, bool sign)
Definition BitFloat.h:70
casacore::BitFloat::Match
friend constexpr std::optional< BitFloat > Match(const BitFloat &input, int8_t value_exponent)
Shifts the input value such that its exponent matches the specified exponent.
Definition BitFloat.h:245
casacore::BitFloat::operator+=
constexpr BitFloat & operator+=(const BitFloat &rhs)
Adds the value rhs to this.
Definition BitFloat.h:129
casacore::BitFloat::Exponent
constexpr int8_t Exponent() const
Definition BitFloat.h:75
casacore::BitFloat::AllowsMath
static constexpr bool AllowsMath(int8_t exponent)
Based on the exponent, determines if this is a special value and should not be used in mathematical o...
Definition BitFloat.h:216
casacore::BitFloat::operator/=
constexpr BitFloat & operator/=(unsigned factor)
Divides the value by an integer factor.
Definition BitFloat.h:169
casacore::BitFloat::operator-
friend constexpr BitFloat operator-(const BitFloat &input)
Negation; flips the sign of the value.
Definition BitFloat.h:225
casacore::BitFloat::sign_
bool sign_
Definition BitFloat.h:298
casacore::BitFloat::BitFloat
constexpr BitFloat(float f)
Constructs a BitFloat by decomposing the specified floating point value.
Definition BitFloat.h:61
casacore::BitFloat::mantissa_
uint32_t mantissa_
Definition BitFloat.h:296
casacore::BitFloat::ToFloat
constexpr float ToFloat() const
Compose this value back into a single-precision floating point value.
Definition BitFloat.h:181
casacore::BitFloat::Mantissa
constexpr uint32_t Mantissa() const
Definition BitFloat.h:73
casacore::BitFloat::AllowsMath
constexpr bool AllowsMath() const
Definition BitFloat.h:220
casacore::Normal
Normal or Gaussian distribution.
Definition Random.h:996
casacore
this file contains all the compiler specific defines
Definition mainpage.dox:28
casacore::ToString
constexpr std::string_view ToString(BitFloatKind kind)
Definition BitFloat.h:24
casacore::sign
LatticeExprNode sign(const LatticeExprNode &expr)
casacore::factor
int * factor
Definition hdu.h:478
casacore::BitFloatKind
BitFloatKind
Definition BitFloat.h:13
casacore::BitFloatKind::NegativeZero
@ NegativeZero
Definition BitFloat.h:15
casacore::BitFloatKind::SignallingNaN
@ SignallingNaN
Definition BitFloat.h:18
casacore::BitFloatKind::NaN
@ NaN
Definition BitFloat.h:17
casacore::BitFloatKind::Normal
@ Normal
Definition BitFloat.h:16
casacore::BitFloatKind::NegativeInfinity
@ NegativeInfinity
Definition BitFloat.h:20
casacore::BitFloatKind::Subnormal
@ Subnormal
Definition BitFloat.h:21
casacore::BitFloatKind::Zero
@ Zero
Definition BitFloat.h:14
casacore::BitFloatKind::Infinity
@ Infinity
Definition BitFloat.h:19
casacore::value
NewDelAllocator< T > NewDelAllocator< T >::value
Definition Allocator.h:369
std
Define real & complex conjugation for non-complex types and put comparisons into std namespace.
Definition Complex.h:350