ATLAS Offline Software
Public Types | Public Member Functions | Private Attributes | List of all members
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 uint32_t Packdest
 Type into which we pack. More...
 

Public Member Functions

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

Private Attributes

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

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:

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

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 213 of file FloatPacker.cxx.

218  : m_nmantissa (nmantissa),
219  m_scale (scale),
220  m_is_signed (is_signed),
221  m_round (round)
222 {
223  // scale==0 means not to scale.
224  // Use that instead of 1 since it's faster to test for 0.
225  if (scale == 1)
226  scale = 0;
227 
228  if (scale == 0)
229  m_invscale = 0;
230  else
231  m_invscale = 1. / m_scale;
232 
233  // Set up other cached values.
235  if (m_is_signed)
236  --m_npack;
237 
238  m_npack_ones = ones<Packdest> (m_npack);
239 
240  // Sign bit mask.
241  if (m_is_signed)
242  m_signmask = 1U << (nbits - 1);
243  else
244  m_signmask = 0;
245 
246  // Number of exponent bits.
247  m_nexp = nbits - m_nmantissa;
248  m_nexp_ones = ones<Packdest> (m_nexp);
249 
250  // Minimum exponent value.
251  m_min_exp = min_int (m_nexp);
252 
253  // Maximum exponent value.
254  m_max_exp = max_int (m_nexp);
255 
256  if (m_npack < 1 || m_npack > nbits)
257  throw std::runtime_error ("Bad number of mantissa bits.");
258 }

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 271 of file FloatPacker.cxx.

272 {
273  double_or_int d;
274  d.d.d = src;
275 
276  // Fast-path for zero. (Purely an optimization.)
277  // Note: can't use a double compare here. On some architectures (eg, MIPS)
278  // a denormal will compare equal to zero.
279  if (d.i[0] == 0 && d.i[1] == 0)
280  return 0;
281 
282  // Check for NaN and infinity.
283  if (d.d.ieee.exponent == ieee754_double_exponent_mask) {
284  if (err) {
285  std::ostringstream os;
286  os << "Bad float number: " << src << " (" << std::setbase(16) << d.i[0]
287  << " " << d.i[1] << ")";
288  *err = os.str();
289  }
290  d.d.d = 0;
291  }
292 
293  if (m_invscale)
294  d.d.d *= m_invscale;
295 
296  bool was_negative = false;
297  if (d.d.ieee.negative != 0) {
298  if (m_is_signed) {
299  was_negative = true;
300  d.d.d = -d.d.d;
301  }
302  else {
303  // Don't complain on -0.
304  if (d.d.d < 0 && err) {
305  std::ostringstream os;
306  os << "Float overflow during packing: " << src;
307  *err = os.str();
308  }
309  d.d.d = 0;
310  }
311  }
312 
313  // Check for zero again.
314  // (Also need to preserve the sign; the scale division may
315  // have underflowed.)
316  if (d.i[0] == 0 && d.i[1] == 0) {
317  if (was_negative)
318  return m_signmask;
319  else
320  return 0;
321  }
322 
323  // Get packdest_bits bits of mantissa.
324 
325  Packdest mantissa =
326  (d.d.ieee.mantissa0 << (packdest_bits -
327  ieee754_double_mantissa0_bits)) |
328  (d.d.ieee.mantissa1 >>
329  (ieee754_double_mantissa1_bits -
330  (packdest_bits - ieee754_double_mantissa0_bits)));
331 
332  // Get the unbiased exponent.
333  int exponent =
334  static_cast<int> (d.d.ieee.exponent) - ieee754_double_bias;
335 
336  // Do rounding, if requested.
337  if (m_round) {
338  Packdest lsbmask = (1 << (packdest_bits - m_npack));
339  int roundbit;
340  Packdest roundmask;
341  if (lsbmask > 1) {
342  roundbit = (mantissa & (lsbmask >> 1));
343  roundmask = ~ static_cast<Packdest> (roundbit - 1);
344  }
345  else {
346  roundbit = (d.d.ieee.mantissa1 &
347  ((1 << ((ieee754_double_mantissa1_bits -
348  (packdest_bits -
349  ieee754_double_mantissa0_bits)) - 1))));
350  roundmask = ~ static_cast<Packdest> (0);
351  }
352 
353  if (roundbit != 0) {
354  // Handle the case where it would overflow.
355  if ((mantissa & roundmask) == roundmask) {
356  mantissa >>= 1;
357  mantissa |= roundmask;
358  exponent += 1;
359  }
360 
361  mantissa += lsbmask;
362  }
363  }
364 
365  // If the number is too large, bitch, and reset to the largest number.
366  if (exponent > m_max_exp) {
367  if (err) {
368  std::ostringstream os;
369  os << "Float overflow during packing: " << src;
370  *err = os.str();
371  }
372  exponent = m_max_exp;
373  mantissa = static_cast<Packdest> (~0);
374  }
375 
376  // Handle denormals. (We've already handled the zero case.)
377  if (exponent == - ieee754_double_bias)
378  renormalize_denormal (exponent, mantissa);
379 
380  // If the number is too small, denormalize, or underflow to 0.
381  underflow_to_denormal (m_min_exp, m_round ? m_npack: 0, exponent, mantissa);
382 
383  // Pack in the mantissa bits.
384  Packdest dest = mantissa >> (packdest_bits - m_npack);
385 
386  // The exponent, if desired.
387  if (m_nexp > 0)
388  dest |= ((exponent - m_min_exp) << m_npack);
389 
390  // And the optional sign bit.
391  if (was_negative)
392  dest |= m_signmask;
393 
394  return dest;
395 }

◆ 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 405 of file FloatPacker.cxx.

406 {
407  // Fast-path for 0.
408  if (val == 0)
409  return 0;
410 
411  // Break apart the packed value.
412  bool was_negative = false;
413  if ((val & m_signmask) != 0)
414  was_negative = true;
415 
416  double d;
417 
418  // Fast path for fixed-point representations.
419  if (m_nexp == 0) {
420  Packdest mantissa = (val & m_npack_ones);
421  d = mantissa / ((double)m_npack_ones + 1);
422  if (was_negative)
423  d *= -1;
424  }
425  else {
426  // Get the mantissa.
427  Packdest mantissa = (val & m_npack_ones) << (packdest_bits - m_npack);
428 
429  // General case.
430  // Get the exponent.
431  int exponent = ((val >> m_npack) & m_nexp_ones);
432  exponent += m_min_exp; // unbias.
433 
434  ieee754_double dd;
435 
436  // Handle denormals.
437  if (exponent == m_min_exp) {
438  // Maybe it was -0?
439  if (mantissa == 0) {
440  dd.d = 0;
441  if (was_negative)
442  dd.ieee.negative = 1;
443  return dd.d;
444  }
445 
446  renormalize_denormal (exponent, mantissa);
447  }
448 
449  // Complain about overflow.
450  if (exponent >= max_int (ieee754_double_exponent_bits)) {
451  if (err) {
452  std::ostringstream os;
453  os << "Overflow while unpacking float; exponent: " << exponent;
454  *err = os.str();
455  }
456  exponent = max_int (ieee754_double_exponent_bits) + 1;
457  mantissa = 0; // Infinity.
458  }
459 
460  // Underflow into denormal.
461  underflow_to_denormal ( - ieee754_double_bias, 0,
462  exponent, mantissa);
463 
464  // Pack into a double.
465  dd.ieee.negative = was_negative ? 1 : 0;
466  dd.ieee.exponent = exponent + ieee754_double_bias;
467  dd.ieee.mantissa0 =
468  (mantissa >> (packdest_bits - ieee754_double_mantissa0_bits));
469  dd.ieee.mantissa1 =
470  (mantissa << (ieee754_double_mantissa0_bits -
471  (packdest_bits - ieee754_double_mantissa1_bits)));
472  d = dd.d;
473  }
474 
475  // Set the result.
476  if (m_scale)
477  d *= m_scale;
478  return d;
479 }

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:
WriteCellNoiseToCool.src
src
Definition: WriteCellNoiseToCool.py:513
hist_file_dump.d
d
Definition: hist_file_dump.py:137
MuonGM::round
float round(const float toRound, const unsigned int decimals)
Definition: Mdt.cxx:27
CxxUtils::FloatPacker::m_is_signed
bool m_is_signed
Should we use a sign bit?
Definition: FloatPacker.h:114
perfmonmt-printer.dest
dest
Definition: perfmonmt-printer.py:189
yodamerge_tmp.scale
scale
Definition: yodamerge_tmp.py:138
CxxUtils::FloatPacker::m_npack_ones
Packdest m_npack_ones
Mask with that many low bits set.
Definition: FloatPacker.h:123
CxxUtils::FloatPacker::m_signmask
Packdest m_signmask
Mask containing the sign bit (or 0 if there's no sign bit).
Definition: FloatPacker.h:126
CxxUtils::FloatPacker::m_min_exp
int m_min_exp
Minimum exponent value.
Definition: FloatPacker.h:135
dqt_zlumi_pandas.err
err
Definition: dqt_zlumi_pandas.py:182
CxxUtils::FloatPacker::m_nexp
int m_nexp
Number of exponent bits.
Definition: FloatPacker.h:129
CxxUtils::FloatPacker::m_round
bool m_round
Should we round instead of truncating?
Definition: FloatPacker.h:117
CxxUtils::FloatPacker::Packdest
uint32_t Packdest
Type into which we pack.
Definition: FloatPacker.h:61
xAOD::double
double
Definition: CompositeParticle_v1.cxx:159
ReadFromCoolCompare.os
os
Definition: ReadFromCoolCompare.py:231
library_scraper.dd
list dd
Definition: library_scraper.py:46
CxxUtils::FloatPacker::m_max_exp
int m_max_exp
Maximum exponent value.
Definition: FloatPacker.h:138
CxxUtils::FloatPacker::m_nmantissa
int m_nmantissa
Number of bits in the mantissa + sign bit.
Definition: FloatPacker.h:105
CxxUtils::FloatPacker::m_nexp_ones
Packdest m_nexp_ones
Mask with that many low bits set.
Definition: FloatPacker.h:132
Pythia8_RapidityOrderMPI.val
val
Definition: Pythia8_RapidityOrderMPI.py:14
CxxUtils::FloatPacker::m_invscale
double m_invscale
Inverse of scale.
Definition: FloatPacker.h:111
CxxUtils::FloatPacker::m_npack
int m_npack
Number of bits in mantissa (exclusive of any sign bit).
Definition: FloatPacker.h:120
CxxUtils::FloatPacker::m_scale
double m_scale
Scale factor for stored numbers.
Definition: FloatPacker.h:108