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>(
64 (std::bit_cast<uint32_t>(f) & 0x7F800000) >> 23) -
65 127),
66 sign_(std::bit_cast<uint32_t>(f) & 0x80000000) {
67 if (f == 0.0f) mantissa_ = 0;
68 }
69
70 constexpr BitFloat(uint32_t mantissa, int8_t exponent, bool sign)
71 : mantissa_(mantissa), exponent_(exponent), sign_(sign) {}
72
73 constexpr uint32_t Mantissa() const { return mantissa_; }
74
75 constexpr int8_t Exponent() const { return exponent_; }
76
89 constexpr uint32_t PackMantissa() const {
90 if (MantissaOverflow()) {
91 throw std::overflow_error(
92 "An overflow occured! Value = " + std::to_string(ToFloat()) +
93 ", exponent = " + std::to_string(exponent_) + ", mantissa = " +
94 std::to_string(mantissa_) + ", sign = " + std::to_string(sign_));
95 }
96 return (mantissa_ & 0x7FFFFFFFu) | (sign_ ? 0x80000000u : 0u);
97 }
98
103 constexpr static std::pair<uint32_t, bool> UnpackMantissa(
104 uint32_t mantissa_with_sign) {
105 const uint32_t mantissa = (mantissa_with_sign & 0x7FFFFFFFu);
106 const bool sign = (mantissa_with_sign & 0x80000000u) != 0u;
107 return {mantissa, sign};
108 }
109
115 constexpr static BitFloat FromCompressed(uint32_t mantissa_with_sign,
116 int8_t exponent) {
117 const std::pair<uint32_t, bool> unpacked =
118 UnpackMantissa(mantissa_with_sign);
119 return BitFloat(unpacked.first, exponent, unpacked.second);
120 }
121
122 constexpr bool Sign() const { return sign_; }
123
129 constexpr BitFloat& operator+=(const BitFloat& rhs) {
130 if (sign_ == rhs.sign_) {
132 } else if (mantissa_ >= rhs.mantissa_) {
134 } else {
136 sign_ = !sign_;
137 }
138 return *this;
139 }
140
144 constexpr BitFloat& operator-=(const BitFloat& rhs) {
145 if (sign_ != rhs.sign_) {
147 } else if (mantissa_ >= rhs.mantissa_) {
149 } else {
151 sign_ = !sign_;
152 }
153 return *this;
154 }
155
160 constexpr BitFloat& operator*=(unsigned factor) {
161 mantissa_ *= factor;
162 return *this;
163 }
164
169 constexpr BitFloat& operator/=(unsigned factor) {
170 mantissa_ /= factor;
171 return *this;
172 }
173
181 constexpr float ToFloat() const {
182 int8_t exponent = exponent_;
183 uint32_t result = mantissa_;
184 // Exponent values of +128 and -127 have special meaning.
185 // 128 will be wrapped.
186 if (exponent_ != static_cast<int8_t>(128u) && exponent_ != -127) {
187 if (mantissa_ == 0) return sign_ ? -0.0f : 0.0f;
188 while (result & 0xFF000000) {
189 ++exponent;
190 result = (result >> 1);
191 }
192 while ((result & 0x00800000) == 0) {
193 --exponent;
194 result = (result << 1);
195 }
196 }
197 // The double cast of the exponent is necessary to prevent sign extension.
198 result =
199 (result & 0x007FFFFF) |
200 (static_cast<uint32_t>(static_cast<uint8_t>(exponent + 127)) << 23) |
201 (sign_ ? 0x80000000 : 0x0);
202 return std::bit_cast<float>(result);
203 }
204
205 explicit constexpr operator float() const { return ToFloat(); }
206
216 static constexpr bool AllowsMath(int8_t exponent) {
217 return exponent != static_cast<int8_t>(128u) && exponent != -127;
218 }
219
220 constexpr bool AllowsMath() const { return AllowsMath(exponent_); }
221
225 friend constexpr BitFloat operator-(const BitFloat& input) {
226 return BitFloat(input.mantissa_, input.exponent_, !input.sign_);
227 }
228
229 friend constexpr bool operator==(const BitFloat& lhs, const BitFloat& rhs) {
230 return lhs.mantissa_ == rhs.mantissa_ && lhs.exponent_ == rhs.exponent_ &&
231 lhs.sign_ == rhs.sign_;
232 }
233
245 friend constexpr std::optional<BitFloat> Match(const BitFloat& input,
246 int8_t value_exponent) {
247 if (input.Exponent() == value_exponent) {
248 return input;
249 } else if (input.Exponent() > value_exponent) {
250 const uint8_t shift = input.Exponent() - value_exponent;
251 if (shift > 7)
252 return {};
253 else
254 return BitFloat(input.Mantissa() << shift, value_exponent,
255 input.Sign());
256 } else {
257 const uint8_t shift = value_exponent - input.Exponent();
258 if (shift > 24)
259 return BitFloat(0, value_exponent, input.Sign());
260 else
261 return BitFloat(input.Mantissa() >> shift, value_exponent,
262 input.Sign());
263 }
264 }
265
267 constexpr bool MantissaOverflow() const { return mantissa_ & 0x80000000; }
268
271 constexpr static BitFloatKind GetKind(float f) {
272 const uint32_t value = std::bit_cast<uint32_t>(f);
273 if (value == 0) {
274 return BitFloatKind::Zero;
275 } else if (value == 0x80000000) {
277 } else if ((value & 0x7F800000) == 0x7F800000) {
278 // exponent is 128
279 if (value & 0x00400000)
280 return BitFloatKind::NaN;
281 else
283 } else if ((value & 0x7FFFFFFF) == 0b1111111100000000000000000000000) {
284 if (value & 0x80000000)
286 else
288 } else if ((value & 0x7F800000) == 0) {
290 } else {
292 }
293 }
294
295 private:
296 uint32_t mantissa_;
297 int8_t exponent_;
298 bool sign_;
299};
300
301} // namespace casacore
302
303#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:115
constexpr BitFloat & operator-=(const BitFloat &rhs)
Like operator+=, but subtracts rhs.
Definition BitFloat.h:144
constexpr bool Sign() const
Definition BitFloat.h:122
constexpr bool MantissaOverflow() const
Returns true if bit 32 is set.
Definition BitFloat.h:267
constexpr uint32_t PackMantissa() const
Combines the sign and the mantissa into one uint32_t.
Definition BitFloat.h:89
constexpr BitFloat()
Constructs a zero-value BitFloat.
Definition BitFloat.h:57
friend constexpr bool operator==(const BitFloat &lhs, const BitFloat &rhs)
Definition BitFloat.h:229
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
constexpr BitFloat & operator*=(unsigned factor)
Multiplies the value by an integer factor.
Definition BitFloat.h:160
static constexpr BitFloatKind GetKind(float f)
Determine what kind of float the specified value is: normal, nan, inf, etc.
Definition BitFloat.h:271
constexpr BitFloat(uint32_t mantissa, int8_t exponent, bool sign)
Definition BitFloat.h:70
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
constexpr BitFloat & operator+=(const BitFloat &rhs)
Adds the value rhs to this.
Definition BitFloat.h:129
constexpr int8_t Exponent() const
Definition BitFloat.h:75
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
constexpr BitFloat & operator/=(unsigned factor)
Divides the value by an integer factor.
Definition BitFloat.h:169
friend constexpr BitFloat operator-(const BitFloat &input)
Negation; flips the sign of the value.
Definition BitFloat.h:225
constexpr BitFloat(float f)
Constructs a BitFloat by decomposing the specified floating point value.
Definition BitFloat.h:61
uint32_t mantissa_
Definition BitFloat.h:296
constexpr float ToFloat() const
Compose this value back into a single-precision floating point value.
Definition BitFloat.h:181
constexpr uint32_t Mantissa() const
Definition BitFloat.h:73
constexpr bool AllowsMath() const
Definition BitFloat.h:220
Normal or Gaussian distribution.
Definition Random.h:996
this file contains all the compiler specific defines
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:478
NewDelAllocator< T > NewDelAllocator< T >::value
Definition Allocator.h:368
Define real & complex conjugation for non-complex types and put comparisons into std namespace.
Definition Complex.h:350