ATLAS Offline Software
Loading...
Searching...
No Matches
CxxUtils::FloatPacker Class Reference

Pack/unpack floating-point data from/to a given number of bits. More...

#include <FloatPacker.h>

Collaboration diagram for CxxUtils::FloatPacker:

Public Types

typedef std::uint32_t Packdest
 Type into which we pack.

Public Member Functions

 FloatPacker (int nbits, int nmantissa, double scale=1, bool is_signed=true, bool round=false)
 Constructor.
Packdest pack (double src, std::string *err=nullptr) const
 Pack a value.
double unpack (Packdest val, std::string *err=nullptr) const
 Unpack the value VAL.

Private Attributes

int m_nmantissa
 Number of bits in the mantissa + sign bit.
double m_scale
 Scale factor for stored numbers.
double m_invscale
 Inverse of scale.
bool m_is_signed
 Should we use a sign bit?
bool m_round
 Should we round instead of truncating?
int m_npack
 Number of bits in mantissa (exclusive of any sign bit).
Packdest m_npack_ones
 Mask with that many low bits set.
Packdest m_signmask
 Mask containing the sign bit (or 0 if there's no sign bit).
int m_nexp
 Number of exponent bits.
Packdest m_nexp_ones
 Mask with that many low bits set.
int m_min_exp
 Minimum exponent value.
int m_max_exp
 Maximum exponent value.

Detailed Description

Pack/unpack floating-point data from/to a given number of bits.

The format is specified by the following parameters.

nbits - The total number of bits in the representation. scale - Scale factor to apply before storing. nmantissa - The number of bits to use for the mantissa and sign bit. is_signed - Flag to tell if we should use a sign bit. round - Flag to tell if we should round or truncate.

From these we derive:

npack = nmantissa, if is_signed is false. = nmantissa-1 if is_signed is true. nexp = nbits - nmantissa

The format consists of, in order from high bits to low bits:

  • A sign bit, if is_signed is true.
  • nexp bits of exponent information.
  • npack bits of mantissa.

The number is stored in normalized form, with an exponent bias of 2^(nexp-1). But if the (biased) exponent is zero, then the mantissa is stored in denormalized form. If nexp==0, this gives a fixed-point representation in the range [0,1). 0 is represented by all bits 0; if we have a sign bit, we can also represent -0 by all bits 0 except for the sign bit.

Definition at line 57 of file FloatPacker.h.

Member Typedef Documentation

◆ Packdest

typedef std::uint32_t CxxUtils::FloatPacker::Packdest

Type into which we pack.

Definition at line 61 of file FloatPacker.h.

Constructor & Destructor Documentation

◆ FloatPacker()

CxxUtils::FloatPacker::FloatPacker ( int nbits,
int nmantissa,
double scale = 1,
bool is_signed = true,
bool round = false )

Constructor.

Parameters
nbitsThe number of bits in the packed representation.
nmantissaThe number of bits to use for the mantissa and sign bit.
scaleDivide the input number by this before packing.
is_signedIf true, then one mantissa bit is used for a sign.
roundIf true, numbers will be rounded. Otherwise, they will be truncated.

Definition at line 214 of file FloatPacker.cxx.

219 : m_nmantissa (nmantissa),
220 m_scale (scale),
221 m_is_signed (is_signed),
222 m_round (round)
223{
224 // scale==0 means not to scale.
225 // Use that instead of 1 since it's faster to test for 0.
226 if (scale == 1 || scale == 0)
227 m_invscale = 0;
228 else {
229 // Avoid spurious div-zero FPEs with clang.
231 m_invscale = 1. / m_scale;
232 }
233
234 // Set up other cached values.
236 if (m_is_signed)
237 --m_npack;
238
240
241 // Sign bit mask.
242 if (m_is_signed)
243 m_signmask = 1U << (nbits - 1);
244 else
245 m_signmask = 0;
246
247 // Number of exponent bits.
248 m_nexp = nbits - m_nmantissa;
250
251 // Minimum exponent value.
252 m_min_exp = min_int (m_nexp);
253
254 // Maximum exponent value.
255 m_max_exp = max_int (m_nexp);
256
257 if (m_npack < 1 || m_npack > nbits)
258 throw std::runtime_error ("Bad number of mantissa bits.");
259}
int m_nmantissa
Number of bits in the mantissa + sign bit.
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.
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.
Definition ones.h:25
#define CXXUTILS_TRAPPING_FP
Definition trapping_fp.h:24

Member Function Documentation

◆ pack()

FloatPacker::Packdest CxxUtils::FloatPacker::pack ( double src,
std::string * err = nullptr ) const

Pack a value.

Parameters
srcValue to pack.
errIf non-null, then this string will be set to a description of any error that occurs.
Returns
The packed value.

For now, we convert floats to doubles before packing.

Definition at line 272 of file FloatPacker.cxx.

273{
274 double d = src;
275 std::uint64_t bits = doubleToBits(d);
276
277 // Fast-path for zero. (Purely an optimization.)
278 // Note: can't use a double compare here. On some architectures (eg, MIPS)
279 // a denormal will compare equal to zero.
280 if (bits == 0) {
281 return 0;
282 }
283
284 // Check for NaN and infinity.
285 if (biasedExponent(bits) == ieee754_double_exponent_all_ones) {
286 if (err) {
287 *err = std::format ("Bad float number: {} ({:#010x} {:#010x})",
288 src,
289 static_cast<std::uint32_t>(bits),
290 static_cast<std::uint32_t>(bits >> 32));
291 }
292 d = 0;
293 bits = doubleToBits(d);
294 }
295
296 if (m_invscale){
297 d *= m_invscale;
298 bits = doubleToBits(d);
299 }
300 bool was_negative = false;
301 if (isNegativeBits(bits)) {
302 if (m_is_signed) {
303 was_negative = true;
304 d = -d;
305 bits = doubleToBits(d);
306 }
307 else {
308 // Don't complain on -0.
309 if (d < 0 && err) {
310 *err = std::format ("Float overflow during packing: {}", src);
311 }
312 d = 0;
313 bits = doubleToBits(d);
314 }
315 }
316
317 // Check for zero again.
318 // (Also need to preserve the sign; the scale division may
319 // have underflowed.)
320 if (isZeroBits(bits)) {
321 return was_negative ? m_signmask : 0;
322 }
323
324 // Get packdest_bits bits of mantissa.
325 const std::uint64_t fullMantissa = doubleMantissaBits(bits);
326 Packdest mantissa = static_cast<Packdest>(
327 fullMantissa >> (ieee754_double_mantissa_bits - packdest_bits));
328 int exponent = biasedExponent(bits) - ieee754_double_bias;
329
330 // Do rounding, if requested.
331 if (m_round) {
332 const Packdest lsbmask = Packdest{1} << (packdest_bits - m_npack);
333 Packdest roundmask = ~Packdest{0};
334 bool roundbit = false;
335
336 if (lsbmask > 1) {
337 roundbit = (mantissa & (lsbmask >> 1)) != 0;
338 roundmask = ~static_cast<Packdest>((lsbmask >> 1) - 1);
339 }
340 else {
341 // We are keeping all packdest_bits bits of the extracted mantissa.
342 // The rounding bit is therefore the next bit below those bits in the
343 // original 52-bit double mantissa.
344 constexpr int shift = ieee754_double_mantissa_bits - packdest_bits;
345 roundbit = (fullMantissa & (std::uint64_t{1} << (shift - 1))) != 0;
346 }
347
348 if (roundbit) {
349 // Handle the case where it would overflow.
350 if ((mantissa & roundmask) == roundmask) {
351 mantissa >>= 1;
352 mantissa |= roundmask;
353 exponent += 1;
354 }
355
356 mantissa += lsbmask;
357 }
358 }
359
360 // If the number is too large, bitch, and reset to the largest number.
361 if (exponent > m_max_exp) {
362 if (err) {
363 *err = std::format ("Float overflow during packing: {}", src);
364 }
365 exponent = m_max_exp;
366 mantissa = static_cast<Packdest> (~0);
367 }
368
369 // Handle denormals. (We've already handled the zero case.)
370 if (exponent == - ieee754_double_bias)
371 renormalize_denormal (exponent, mantissa);
372
373 // If the number is too small, denormalize, or underflow to 0.
374 underflow_to_denormal (m_min_exp, m_round ? m_npack: 0, exponent, mantissa);
375
376 // Pack in the mantissa bits.
377 Packdest dest = mantissa >> (packdest_bits - m_npack);
378
379 // The exponent, if desired.
380 if (m_nexp > 0)
381 dest |= ((exponent - m_min_exp) << m_npack);
382
383 // And the optional sign bit.
384 if (was_negative)
385 dest |= m_signmask;
386
387 return dest;
388}
std::uint32_t Packdest
Type into which we pack.
Definition FloatPacker.h:61
virtual void shift(size_t pos, ptrdiff_t offs) override
Shift the elements of the container.

◆ unpack()

double CxxUtils::FloatPacker::unpack ( Packdest val,
std::string * err = nullptr ) const

Unpack the value VAL.

Parameters
valThe packed data. It should start with the low bit, and any extraneous bits should have been masked off.
errIf non-null, then this string will be set to a description of any error that occurs.

Definition at line 399 of file FloatPacker.cxx.

400{
401 // Fast-path for 0.
402 if (val == 0) {
403 return 0;
404 }
405
406 // Break apart the packed value.
407 const bool was_negative = (val & m_signmask) != 0;
408
409 double d = 0;
410
411 // Fast path for fixed-point representations.
412 if (m_nexp == 0) {
413 const Packdest mantissa = val & m_npack_ones;
414 d = mantissa / (static_cast<double>(m_npack_ones) + 1);
415
416 if (was_negative) {
417 d *= -1;
418 }
419 }
420 else {
421 // Get the mantissa.
422 Packdest mantissa = (val & m_npack_ones) << (packdest_bits - m_npack);
423 // General case.
424 // Get the exponent.
425 int exponent = static_cast<int>((val >> m_npack) & m_nexp_ones);
426 exponent += m_min_exp; // unbias.
427
428 // Handle denormals.
429 if (exponent == m_min_exp) {
430 // Maybe it was -0?
431 if (mantissa == 0) {
432 std::uint64_t bits = 0;
433 if (was_negative) {
434 bits |= double_sign_mask;
435 }
436 return bitsToDouble(bits);
437 }
438 renormalize_denormal(exponent, mantissa);
439 }
440 // Complain about overflow.
441 if (exponent >= max_int(ieee754_double_exponent_bits)) {
442 if (err) {
443 *err = std::format ("Overflow while unpacking float; exponent: {}", exponent);
444 }
445 exponent = max_int(ieee754_double_exponent_bits) + 1;
446 mantissa = 0; // Infinity.
447 }
448 // Underflow into denormal.
449 underflow_to_denormal(-ieee754_double_bias, 0, exponent, mantissa);
450 // Pack into a double.
451 std::uint64_t bits = 0;
452 if (was_negative) {
453 bits |= double_sign_mask;
454 }
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);
460 }
461 // Set the result.
462 if (m_scale) {
463 d *= m_scale;
464 }
465 return d;
466}

Member Data Documentation

◆ m_invscale

double CxxUtils::FloatPacker::m_invscale
private

Inverse of scale.

Definition at line 111 of file FloatPacker.h.

◆ m_is_signed

bool CxxUtils::FloatPacker::m_is_signed
private

Should we use a sign bit?

Definition at line 114 of file FloatPacker.h.

◆ m_max_exp

int CxxUtils::FloatPacker::m_max_exp
private

Maximum exponent value.

Definition at line 138 of file FloatPacker.h.

◆ m_min_exp

int CxxUtils::FloatPacker::m_min_exp
private

Minimum exponent value.

Definition at line 135 of file FloatPacker.h.

◆ m_nexp

int CxxUtils::FloatPacker::m_nexp
private

Number of exponent bits.

Definition at line 129 of file FloatPacker.h.

◆ m_nexp_ones

Packdest CxxUtils::FloatPacker::m_nexp_ones
private

Mask with that many low bits set.

Definition at line 132 of file FloatPacker.h.

◆ m_nmantissa

int CxxUtils::FloatPacker::m_nmantissa
private

Number of bits in the mantissa + sign bit.

Definition at line 105 of file FloatPacker.h.

◆ m_npack

int CxxUtils::FloatPacker::m_npack
private

Number of bits in mantissa (exclusive of any sign bit).

Definition at line 120 of file FloatPacker.h.

◆ m_npack_ones

Packdest CxxUtils::FloatPacker::m_npack_ones
private

Mask with that many low bits set.

Definition at line 123 of file FloatPacker.h.

◆ m_round

bool CxxUtils::FloatPacker::m_round
private

Should we round instead of truncating?

Definition at line 117 of file FloatPacker.h.

◆ m_scale

double CxxUtils::FloatPacker::m_scale
private

Scale factor for stored numbers.

Definition at line 108 of file FloatPacker.h.

◆ m_signmask

Packdest CxxUtils::FloatPacker::m_signmask
private

Mask containing the sign bit (or 0 if there's no sign bit).

Definition at line 126 of file FloatPacker.h.


The documentation for this class was generated from the following files: