25 static_assert(std::numeric_limits<double>::is_iec559);
26 static_assert(std::numeric_limits<double>::digits == 53);
27 static_assert(std::numeric_limits<Packdest>::digits == 32);
29 constexpr std::uint64_t double_sign_mask = 0x8000000000000000ULL;
30 constexpr std::uint64_t double_exponent_mask = 0x7ff0000000000000ULL;
31 constexpr std::uint64_t double_mantissa_mask = 0x000fffffffffffffULL;
33 constexpr int ieee754_double_bias = 0x3ff;
34 constexpr int ieee754_double_exponent_bits = 11;
35 constexpr int ieee754_double_mantissa_bits = 52;
36 constexpr int ieee754_double_exponent_shift = 52;
38 constexpr std::uint64_t
39 doubleToBits(
double value)
noexcept
41 return std::bit_cast<std::uint64_t>(value);
45 bitsToDouble(std::uint64_t bits)
noexcept
47 return std::bit_cast<double>(bits);
51 isZeroBits(std::uint64_t bits)
noexcept
53 return (bits & ~double_sign_mask) == 0;
57 isNegativeBits(std::uint64_t bits)
noexcept
59 return (bits & double_sign_mask) != 0;
63 biasedExponent(std::uint64_t bits)
noexcept
65 return static_cast<int>(
66 (bits & double_exponent_mask) >> ieee754_double_exponent_shift);
69 constexpr std::uint64_t
70 doubleMantissaBits(std::uint64_t bits)
noexcept
72 return bits & double_mantissa_mask;
78 const int packdest_bits = std::numeric_limits<Packdest>::digits;
82 const Packdest high_packdest_bit = (1U << (packdest_bits - 1));
84 const Packdest ieee754_double_exponent_all_ones =
85 (Packdest{1} << ieee754_double_exponent_bits) - 1;
95 int max_int (
int nbits)
97 return ((1U << nbits) >> 1) - 1;
108 int min_int (
int nbits)
110 return static_cast<int>(~0U << nbits) >> 1;
122 void renormalize_denormal (
int& exponent,
126 exponent -= packdest_bits;
128 while ((mantissa & high_packdest_bit) == 0) {
149 void underflow_to_denormal (
int min_exp,
154 if (exponent <= min_exp) {
155 const Packdest mantissa_in = mantissa;
158 mantissa = (mantissa >> 1) | high_packdest_bit;
161 int shift = min_exp - exponent;
162 if (shift < packdest_bits)
181 int orig_pos = packdest_bits - round_bits +
shift;
182 if (orig_pos < packdest_bits &&
183 ((
static_cast<Packdest
> (1) << orig_pos) & mantissa_in) != 0)
185 Packdest lsb = (
static_cast<Packdest
> (1) <<
186 (packdest_bits - round_bits));
187 Packdest lsbmask = ~ (lsb - 1);
191 if ((mantissa & lsbmask) != lsbmask)
227 if (scale == 1 || scale == 0)
259 throw std::runtime_error (
"Bad number of mantissa bits.");
276 std::uint64_t bits = doubleToBits(d);
286 if (biasedExponent(bits) == ieee754_double_exponent_all_ones) {
288 std::ostringstream os;
289 os <<
"Bad float number: " << src <<
" ("
291 <<
static_cast<std::uint32_t
>(bits)
293 <<
static_cast<std::uint32_t
>(bits >> 32)
298 bits = doubleToBits(d);
303 bits = doubleToBits(d);
305 bool was_negative =
false;
306 if (isNegativeBits(bits)) {
310 bits = doubleToBits(d);
315 std::ostringstream os;
316 os <<
"Float overflow during packing: " << src;
320 bits = doubleToBits(d);
327 if (isZeroBits(bits)) {
332 const std::uint64_t fullMantissa = doubleMantissaBits(bits);
334 fullMantissa >> (ieee754_double_mantissa_bits - packdest_bits));
335 int exponent = biasedExponent(bits) - ieee754_double_bias;
341 bool roundbit =
false;
344 roundbit = (mantissa & (lsbmask >> 1)) != 0;
345 roundmask = ~static_cast<Packdest>((lsbmask >> 1) - 1);
351 constexpr int shift = ieee754_double_mantissa_bits - packdest_bits;
352 roundbit = (fullMantissa & (std::uint64_t{1} << (shift - 1))) != 0;
357 if ((mantissa & roundmask) == roundmask) {
359 mantissa |= roundmask;
370 std::ostringstream os;
371 os <<
"Float overflow during packing: " << src;
375 mantissa =
static_cast<Packdest> (~0);
379 if (exponent == - ieee754_double_bias)
380 renormalize_denormal (exponent, mantissa);
416 const bool was_negative = (val &
m_signmask) != 0;
441 std::uint64_t bits = 0;
443 bits |= double_sign_mask;
445 return bitsToDouble(bits);
447 renormalize_denormal(exponent, mantissa);
450 if (exponent >= max_int(ieee754_double_exponent_bits)) {
452 std::ostringstream os;
453 os <<
"Overflow while unpacking float; exponent: " << exponent;
456 exponent = max_int(ieee754_double_exponent_bits) + 1;
460 underflow_to_denormal(-ieee754_double_bias, 0, exponent, mantissa);
462 std::uint64_t bits = 0;
464 bits |= double_sign_mask;
466 bits |=
static_cast<std::uint64_t
>(exponent + ieee754_double_bias)
467 << ieee754_double_exponent_shift;
468 bits |=
static_cast<std::uint64_t
>(mantissa)
469 << (ieee754_double_mantissa_bits - packdest_bits);
470 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