casacore
Loading...
Searching...
No Matches
BitFloat.h
Go to the documentation of this file.
1#ifndef SISCO_BIT_FLOAT_H_
2#define SISCO_BIT_FLOAT_H_
3
4#include <bit>
5#include <cinttypes>
6#include <limits>
7#include <optional>
8#include <stdexcept>
9#include <string_view>
10
11namespace casacore {
12
23
24constexpr std::string_view ToString(BitFloatKind kind) {
25 switch (kind) {
27 return "zero";
29 return "negative zero";
31 return "normal";
33 return "nan";
35 return "signalling nan";
37 return "infinity";
39 return "negative infinity";
41 return "subnormal";
42 }
43 __builtin_unreachable();
44}
45
54class BitFloat {
55 public:
57 constexpr BitFloat() : mantissa_(0), exponent_(-127), sign_(false) {}
58
61 constexpr explicit BitFloat(float f)
62 : mantissa_((std::bit_cast<uint32_t>(f) & 0x007FFFFF) | 0x00800000),
63 exponent_(static_cast<int8_t>((std::bit_cast<uint32_t>(f) & 0x7F800000) >> 23) - 127),
64 sign_(std::bit_cast<uint32_t>(f) & 0x80000000) {
65 if (f == 0.0f) mantissa_ = 0;
66 }
67
68 constexpr BitFloat(uint32_t mantissa, int8_t exponent, bool sign)
69 : mantissa_(mantissa), exponent_(exponent), sign_(sign) {}
70
71 constexpr uint32_t Mantissa() const { return mantissa_; }
72
73 constexpr int8_t Exponent() const { return exponent_; }
74
87 constexpr uint32_t PackMantissa() const {
88 if (MantissaOverflow()) {
89 throw std::overflow_error("An overflow occured! Value = " + std::to_string(ToFloat()) +
90 ", exponent = " + std::to_string(exponent_) + ", mantissa = " +
91 std::to_string(mantissa_) + ", sign = " + std::to_string(sign_));
92 }
93 return (mantissa_ & 0x7FFFFFFFu) | (sign_ ? 0x80000000u : 0u);
94 }
95
100 constexpr static std::pair<uint32_t, bool> UnpackMantissa(uint32_t mantissa_with_sign) {
101 const uint32_t mantissa = (mantissa_with_sign & 0x7FFFFFFFu);
102 const bool sign = (mantissa_with_sign & 0x80000000u) != 0u;
103 return {mantissa, sign};
104 }
105
111 constexpr static BitFloat FromCompressed(uint32_t mantissa_with_sign, int8_t exponent) {
112 const std::pair<uint32_t, bool> unpacked = UnpackMantissa(mantissa_with_sign);
113 return BitFloat(unpacked.first, exponent, unpacked.second);
114 }
115
116 constexpr bool Sign() const { return sign_; }
117
123 constexpr BitFloat& operator+=(const BitFloat& rhs) {
124 if (sign_ == rhs.sign_) {
126 } else if (mantissa_ >= rhs.mantissa_) {
128 } else {
130 sign_ = !sign_;
131 }
132 return *this;
133 }
134
138 constexpr BitFloat& operator-=(const BitFloat& rhs) {
139 if (sign_ != rhs.sign_) {
141 } else if (mantissa_ >= rhs.mantissa_) {
143 } else {
145 sign_ = !sign_;
146 }
147 return *this;
148 }
149
154 constexpr BitFloat& operator*=(unsigned factor) {
155 mantissa_ *= factor;
156 return *this;
157 }
158
163 constexpr BitFloat& operator/=(unsigned factor) {
164 mantissa_ /= factor;
165 return *this;
166 }
167
175 constexpr float ToFloat() const {
176 int8_t exponent = exponent_;
177 uint32_t result = mantissa_;
178 // Exponent values of +128 and -127 have special meaning.
179 // 128 will be wrapped.
180 if (exponent_ != static_cast<int8_t>(128u) && exponent_ != -127) {
181 if (mantissa_ == 0) return sign_ ? -0.0f : 0.0f;
182 while (result & 0xFF000000) {
183 ++exponent;
184 result = (result >> 1);
185 }
186 while ((result & 0x00800000) == 0) {
187 --exponent;
188 result = (result << 1);
189 }
190 }
191 // The double cast of the exponent is necessary to prevent sign extension.
192 result = (result & 0x007FFFFF) |
193 (static_cast<uint32_t>(static_cast<uint8_t>(exponent + 127)) << 23) |
194 (sign_ ? 0x80000000 : 0x0);
195 return std::bit_cast<float>(result);
196 }
197
198 explicit constexpr operator float() const { return ToFloat(); }
199
209 static constexpr bool AllowsMath(int8_t exponent) {
210 return exponent != static_cast<int8_t>(128u) && exponent != -127;
211 }
212
213 constexpr bool AllowsMath() const { return AllowsMath(exponent_); }
214
218 friend constexpr BitFloat operator-(const BitFloat& input) {
219 return BitFloat(input.mantissa_, input.exponent_, !input.sign_);
220 }
221
222 friend constexpr bool operator==(const BitFloat& lhs, const BitFloat& rhs) {
223 return lhs.mantissa_ == rhs.mantissa_ && lhs.exponent_ == rhs.exponent_ &&
224 lhs.sign_ == rhs.sign_;
225 }
226
238 friend constexpr std::optional<BitFloat> Match(const BitFloat& input, int8_t value_exponent) {
239 if (input.Exponent() == value_exponent) {
240 return input;
241 } else if (input.Exponent() > value_exponent) {
242 const uint8_t shift = input.Exponent() - value_exponent;
243 if (shift > 7)
244 return {};
245 else
246 return BitFloat(input.Mantissa() << shift, value_exponent, input.Sign());
247 } else {
248 const uint8_t shift = value_exponent - input.Exponent();
249 if (shift > 24)
250 return BitFloat(0, value_exponent, input.Sign());
251 else
252 return BitFloat(input.Mantissa() >> shift, value_exponent, input.Sign());
253 }
254 }
255
257 constexpr bool MantissaOverflow() const { return mantissa_ & 0x80000000; }
258
261 constexpr static BitFloatKind GetKind(float f) {
262 const uint32_t value = std::bit_cast<uint32_t>(f);
263 if (value == 0) {
264 return BitFloatKind::Zero;
265 } else if (value == 0x80000000) {
267 } else if ((value & 0x7F800000) == 0x7F800000) {
268 // exponent is 128
269 if (value & 0x00400000)
270 return BitFloatKind::NaN;
271 else
273 } else if ((value & 0x7FFFFFFF) == 0b1111111100000000000000000000000) {
274 if (value & 0x80000000)
276 else
278 } else if ((value & 0x7F800000) == 0) {
280 } else {
282 }
283 }
284
285 private:
286 uint32_t mantissa_;
287 int8_t exponent_;
288 bool sign_;
289};
290
291} // namespace casacore
292
293#endif
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:111
constexpr BitFloat & operator-=(const BitFloat &rhs)
Like operator+=, but subtracts rhs.
Definition BitFloat.h:138
constexpr bool Sign() const
Definition BitFloat.h:116
constexpr bool MantissaOverflow() const
Returns true if bit 32 is set.
Definition BitFloat.h:257
constexpr uint32_t PackMantissa() const
Combines the sign and the mantissa into one uint32_t.
Definition BitFloat.h:87
constexpr BitFloat()
Constructs a zero-value BitFloat.
Definition BitFloat.h:57
friend constexpr bool operator==(const BitFloat &lhs, const BitFloat &rhs)
Definition BitFloat.h:222
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:100
constexpr BitFloat & operator*=(unsigned factor)
Multiplies the value by an integer factor.
Definition BitFloat.h:154
static constexpr BitFloatKind GetKind(float f)
Determine what kind of float the specified value is: normal, nan, inf, etc.
Definition BitFloat.h:261
constexpr BitFloat(uint32_t mantissa, int8_t exponent, bool sign)
Definition BitFloat.h:68
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:238
constexpr BitFloat & operator+=(const BitFloat &rhs)
Adds the value rhs to this.
Definition BitFloat.h:123
constexpr int8_t Exponent() const
Definition BitFloat.h:73
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:209
constexpr BitFloat & operator/=(unsigned factor)
Divides the value by an integer factor.
Definition BitFloat.h:163
friend constexpr BitFloat operator-(const BitFloat &input)
Negation; flips the sign of the value.
Definition BitFloat.h:218
constexpr BitFloat(float f)
Constructs a BitFloat by decomposing the specified floating point value.
Definition BitFloat.h:61
uint32_t mantissa_
Definition BitFloat.h:286
constexpr float ToFloat() const
Compose this value back into a single-precision floating point value.
Definition BitFloat.h:175
constexpr uint32_t Mantissa() const
Definition BitFloat.h:71
constexpr bool AllowsMath() const
Definition BitFloat.h:213
Normal or Gaussian distribution.
Definition Random.h:951
For temporary backward namespace compatibility, use casa as alias for casacore.
Definition mainpage.dox:28
constexpr std::string_view ToString(BitFloatKind kind)
Definition BitFloat.h:24
LatticeExprNode sign(const LatticeExprNode &expr)
int * factor
Definition hdu.h:521
NewDelAllocator< T > NewDelAllocator< T >::value
Definition Allocator.h:360
Define real & complex conjugation for non-complex types and put comparisons into std namespace.
Definition Complex.h:344