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

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

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

409{
410 // Fast-path for 0.
411 if (val == 0) {
412 return 0;
413 }
414
415 // Break apart the packed value.
416 const bool was_negative = (val & m_signmask) != 0;
417
418 double d = 0;
419
420 // Fast path for fixed-point representations.
421 if (m_nexp == 0) {
422 const Packdest mantissa = val & m_npack_ones;
423 d = mantissa / (static_cast<double>(m_npack_ones) + 1);
424
425 if (was_negative) {
426 d *= -1;
427 }
428 }
429 else {
430 // Get the mantissa.
431 Packdest mantissa = (val & m_npack_ones) << (packdest_bits - m_npack);
432 // General case.
433 // Get the exponent.
434 int exponent = static_cast<int>((val >> m_npack) & m_nexp_ones);
435 exponent += m_min_exp; // unbias.
436
437 // Handle denormals.
438 if (exponent == m_min_exp) {
439 // Maybe it was -0?
440 if (mantissa == 0) {
441 std::uint64_t bits = 0;
442 if (was_negative) {
443 bits |= double_sign_mask;
444 }
445 return bitsToDouble(bits);
446 }
447 renormalize_denormal(exponent, mantissa);
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 // Underflow into denormal.
460 underflow_to_denormal(-ieee754_double_bias, 0, exponent, mantissa);
461 // Pack into a double.
462 std::uint64_t bits = 0;
463 if (was_negative) {
464 bits |= double_sign_mask;
465 }
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);
471 }
472 // Set the result.
473 if (m_scale) {
474 d *= m_scale;
475 }
476 return d;
477}

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: