24 static_assert(std::numeric_limits<double>::is_iec559);
25 static_assert(std::numeric_limits<double>::digits == 53);
26 static_assert(std::numeric_limits<Packdest>::digits == 32);
28 constexpr std::uint64_t double_sign_mask = 0x8000000000000000ULL;
29 constexpr std::uint64_t double_exponent_mask = 0x7ff0000000000000ULL;
30 constexpr std::uint64_t double_mantissa_mask = 0x000fffffffffffffULL;
32 constexpr int ieee754_double_bias = 0x3ff;
33 constexpr int ieee754_double_exponent_bits = 11;
34 constexpr int ieee754_double_mantissa_bits = 52;
35 constexpr int ieee754_double_exponent_shift = 52;
37 constexpr std::uint64_t
38 doubleToBits(
double value)
noexcept
40 return std::bit_cast<std::uint64_t>(value);
44 bitsToDouble(std::uint64_t bits)
noexcept
46 return std::bit_cast<double>(bits);
50 isZeroBits(std::uint64_t bits)
noexcept
52 return (bits & ~double_sign_mask) == 0;
56 isNegativeBits(std::uint64_t bits)
noexcept
58 return (bits & double_sign_mask) != 0;
62 biasedExponent(std::uint64_t bits)
noexcept
64 return static_cast<int>(
65 (bits & double_exponent_mask) >> ieee754_double_exponent_shift);
68 constexpr std::uint64_t
69 doubleMantissaBits(std::uint64_t bits)
noexcept
71 return bits & double_mantissa_mask;
77 const int packdest_bits = std::numeric_limits<Packdest>::digits;
81 const Packdest high_packdest_bit = (1U << (packdest_bits - 1));
83 const Packdest ieee754_double_exponent_all_ones =
84 (Packdest{1} << ieee754_double_exponent_bits) - 1;
94 int max_int (
int nbits)
96 return ((1U << nbits) >> 1) - 1;
107 int min_int (
int nbits)
109 return static_cast<int>(~0U << nbits) >> 1;
121 void renormalize_denormal (
int& exponent,
125 exponent -= packdest_bits;
127 while ((mantissa & high_packdest_bit) == 0) {
148 void underflow_to_denormal (
int min_exp,
153 if (exponent <= min_exp) {
154 const Packdest mantissa_in = mantissa;
157 mantissa = (mantissa >> 1) | high_packdest_bit;
160 int shift = min_exp - exponent;
161 if (shift < packdest_bits)
180 int orig_pos = packdest_bits - round_bits +
shift;
181 if (orig_pos < packdest_bits &&
182 ((
static_cast<Packdest
> (1) << orig_pos) & mantissa_in) != 0)
184 Packdest lsb = (
static_cast<Packdest
> (1) <<
185 (packdest_bits - round_bits));
186 Packdest lsbmask = ~ (lsb - 1);
190 if ((mantissa & lsbmask) != lsbmask)
226 if (scale == 1 || scale == 0)
258 throw std::runtime_error (
"Bad number of mantissa bits.");
275 std::uint64_t bits = doubleToBits(d);
285 if (biasedExponent(bits) == ieee754_double_exponent_all_ones) {
287 *err = std::format (
"Bad float number: {} ({:#010x} {:#010x})",
289 static_cast<std::uint32_t
>(bits),
290 static_cast<std::uint32_t
>(bits >> 32));
293 bits = doubleToBits(d);
298 bits = doubleToBits(d);
300 bool was_negative =
false;
301 if (isNegativeBits(bits)) {
305 bits = doubleToBits(d);
310 *err = std::format (
"Float overflow during packing: {}", src);
313 bits = doubleToBits(d);
320 if (isZeroBits(bits)) {
325 const std::uint64_t fullMantissa = doubleMantissaBits(bits);
327 fullMantissa >> (ieee754_double_mantissa_bits - packdest_bits));
328 int exponent = biasedExponent(bits) - ieee754_double_bias;
334 bool roundbit =
false;
337 roundbit = (mantissa & (lsbmask >> 1)) != 0;
338 roundmask = ~static_cast<Packdest>((lsbmask >> 1) - 1);
344 constexpr int shift = ieee754_double_mantissa_bits - packdest_bits;
345 roundbit = (fullMantissa & (std::uint64_t{1} << (shift - 1))) != 0;
350 if ((mantissa & roundmask) == roundmask) {
352 mantissa |= roundmask;
363 *err = std::format (
"Float overflow during packing: {}", src);
366 mantissa =
static_cast<Packdest> (~0);
370 if (exponent == - ieee754_double_bias)
371 renormalize_denormal (exponent, mantissa);
407 const bool was_negative = (val &
m_signmask) != 0;
432 std::uint64_t bits = 0;
434 bits |= double_sign_mask;
436 return bitsToDouble(bits);
438 renormalize_denormal(exponent, mantissa);
441 if (exponent >= max_int(ieee754_double_exponent_bits)) {
443 *err = std::format (
"Overflow while unpacking float; exponent: {}", exponent);
445 exponent = max_int(ieee754_double_exponent_bits) + 1;
449 underflow_to_denormal(-ieee754_double_bias, 0, exponent, mantissa);
451 std::uint64_t bits = 0;
453 bits |= double_sign_mask;
455 bits |=
static_cast<std::uint64_t
>(exponent + ieee754_double_bias)
456 << ieee754_double_exponent_shift;
457 bits |=
static_cast<std::uint64_t
>(mantissa)
458 << (ieee754_double_mantissa_bits - packdest_bits);
459 d = bitsToDouble(bits);
Pack/unpack floating-point data from/to a given number of bits.
int m_nmantissa
Number of bits in the mantissa + sign bit.
double unpack(Packdest val, std::string *err=nullptr) const
Unpack the value VAL.
std::uint32_t Packdest
Type into which we pack.
Packdest pack(double src, std::string *err=nullptr) const
Pack a value.
Packdest m_npack_ones
Mask with that many low bits set.
int m_min_exp
Minimum exponent value.
int m_nexp
Number of exponent bits.
FloatPacker(int nbits, int nmantissa, double scale=1, bool is_signed=true, bool round=false)
Constructor.
bool m_is_signed
Should we use a sign bit?
double m_invscale
Inverse of scale.
int m_npack
Number of bits in mantissa (exclusive of any sign bit).
int m_max_exp
Maximum exponent value.
Packdest m_nexp_ones
Mask with that many low bits set.
Packdest m_signmask
Mask containing the sign bit (or 0 if there's no sign bit).
bool m_round
Should we round instead of truncating?
double m_scale
Scale factor for stored numbers.
constexpr T ones(unsigned int n)
Return a bit mask with the lower n bits set.
virtual void shift(size_t pos, ptrdiff_t offs) override
Shift the elements of the container.
Tell the compiler to optimize assuming that FP may trap.
#define CXXUTILS_TRAPPING_FP