ATLAS Offline Software
Loading...
Searching...
No Matches
FloatCompressor.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// $Id: FloatCompressor.cxx 789425 2016-12-13 10:50:12Z krasznaa $
6
7
8
9// Local include(s):
11// System include(s):
12#include <cmath>
13#include <bit>
14
15namespace CxxUtils {
16
18 constexpr unsigned int NMANTISSA = 23;
19
20 FloatCompressor::FloatCompressor( unsigned int mantissaBits )
21 : m_mantissaBits( mantissaBits ), m_mantissaBitmask( 0 ) {
22
23 // IEEE754 single-precision float
24 // SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
25 // F F 8 0 0 0 7 F
26
27 // Definition:
28 //
29 // Assume that we'd like to keep only 7 bits in the mantissa
30 // In this case the memory layout of the bits will be:
31 //
32 // Sign | Exp (8 bits) | Frac (23 bits)
33 // S EEEEEEEE FFFFFFLRTTTTTTTTTTTTTTT
34 //
35 // where
36 //
37 // S : Sign bit
38 // E : Exponent bits
39 // F : Fraction bits
40 // L : Least significant bit (lsb) for 7 bits mantissa precision
41 // R : Rounding bit
42 // T : Sticky bits (i.e any bit after lsb + 1)
43 //
44 // In the current implementation there are essentially 4 cases:
45 //
46 // Case 1: L = 0 and R = 0
47 // In this case there'll be rounding down
48 //
49 // Case 2: L = 1 and R = 0
50 // In this case there'll be rounding down
51 //
52 // Case 3: L = 0 and R = 1
53 // In this case there'll be rounding up
54 //
55 // Note: This scenario can be different than bfloat16 implementation
56 // of TensorFlow, where they round down if all the Ts are zero.
57 // Otherwise, they also round up.
58 //
59 // Case 4: L = 1 and R = 1
60 // In this case there'll be rounding up
61 //
62 // In all cases, we do an extra check to avoid overflow.
63 //
64 // From a technical point of view, the rounding is computed
65 // to be the half of the lsb(=1) and added to the original value
66 // as long as the new value doesn't overflow. Then the
67 // undesired bits are masked. We never go below 5 bits in the
68 // mantissa.
69
70 // Adjust the received bit number to some reasonable value:
71 if( m_mantissaBits < 5 ) {
73 }
76 }
77
78 // Fill up the lower N bits:
79 for( unsigned int i = 0; i < ( NMANTISSA - m_mantissaBits ); ++i ) {
80 m_mantissaBitmask |= ( 0x1 << i );
81 }
82 // And now negate it to get the correct mask:
84
85 // Set the Magic numbers
87 m_rounding = 0;
88 }
89 else {
90 m_rounding = 0x1 << ( 32 - (1 + 8 + m_mantissaBits) - 1 );
91 }
92 // The part below is taken from AthenaPoolCnvSvc/Compressor
93 // and would work the same as long as the user doesn't
94 // compress lower than 3 mantissa bits, which is not allowed
95 // in any case.
96 m_vmax = 0x7f7 << 20;
97 m_vmax |= 0x000fffff xor (m_rounding);
98 }
99
100 float FloatCompressor::reduceFloatPrecision( float value ) const {
101
102 // Check if any compression is to be made:
103 if( m_mantissaBits == NMANTISSA ) {
104 return value;
105 }
106
107 // Check for NaN, etc:
108 if( ! std::isfinite( value ) ) {
109 return value;
110 }
111
112 auto ivalue = std::bit_cast<std::uint32_t>( value );
113
114 //safety-check if value (omitting the sign-bit) is lower than vmax
115 //(avoid overflow)
116 if( ( ivalue & std::uint32_t{0x7fffffff} ) < m_vmax ) {
117 ivalue += m_rounding;
118 }
119
120 // Do the compression:
121 ivalue &= m_mantissaBitmask;
122 return std::bit_cast<float>( ivalue );
123 }
124
125} // namespace CxxUtils
unsigned int m_mantissaBits
Number of mantissa bits to keep.
uint32_t m_vmax
Largest possible positive 32bit float minus the rounding.
uint32_t m_mantissaBitmask
Bitmask for zeroing out the non-interesting bits.
float reduceFloatPrecision(float value) const
Function returning a reduced precision float value.
FloatCompressor(unsigned int mantissaBits=7)
Constructor with the number of mantissa bits to retain.
constexpr unsigned int NMANTISSA
Total number of total mantissa bits.