Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 10:50:36

0001 #ifndef liblogintpack_h
0002 #define liblogintpack_h
0003 
0004 #include <cmath>
0005 #include <cstdint>
0006 
0007 namespace logintpack {
0008   constexpr int8_t smallestPositive = 0;
0009   // note that abs(unpack(smallestNegative)) == unpack(1), i.e. there
0010   // is no "x" such that "unpack(x) == -unpack(0)"
0011   constexpr int8_t smallestNegative = -1;
0012   inline int16_t pack16logCeil(double x, double lmin, double lmax, uint16_t base = 32768) {
0013     if (base > 32768)
0014       base = 32768;
0015     const double l = std::log(std::abs(x));
0016     const double centered = (l - lmin) / (lmax - lmin) * base;
0017     int16_t r = std::ceil(centered);
0018     if (centered >= base - 1)
0019       r = base - 1;
0020     if (centered < 0)
0021       r = 0;
0022     if (x < 0)
0023       r = r == 0 ? -1 : -r;
0024     return r;
0025   }
0026 
0027   inline int16_t pack16log(double x, double lmin, double lmax, uint16_t base = 32768) {
0028     if (base > 32768)
0029       base = 32768;
0030     const float delta = (log(1. + exp((lmax - lmin) / base)) - log(2.)) * base / (lmax - lmin);
0031     const double l = std::log(std::abs(x));
0032     const double centered = (l - lmin) / (lmax - lmin) * base;
0033     int16_t r = std::floor(centered);
0034     if (centered - r > delta)
0035       r += 1;
0036     if (centered >= base - 1)
0037       r = base - 1;
0038     if (centered < 0)
0039       r = 0;
0040     if (x < 0)
0041       r = r == 0 ? -1 : -r;
0042     return r;
0043   }
0044 
0045   /// pack a value x distributed in [-1,1], with guarantee that -1 and 1 are preserved exactly in packing and unpacking.
0046   /// tries to keep the best precision for x close to the endpoints, sacrifying that in the middle
0047   inline int16_t pack16logClosed(double x, double lmin, double lmax, uint16_t base = 32768) {
0048     if (base > 32768)
0049       base = 32768;
0050     const double l = std::log(std::abs(x));
0051     const double centered = (l - lmin) / (lmax - lmin) * (base - 1);
0052     int16_t r = round(centered);
0053     if (centered >= base - 1)
0054       r = base - 1;
0055     if (centered < 0)
0056       r = 0;
0057     if (x < 0)
0058       r = r == 0 ? -1 : -r;
0059     return r;
0060   }
0061 
0062   inline double unpack16log(int16_t i, double lmin, double lmax, uint16_t base = 32768) {
0063     if (base > 32768)
0064       base = 32768;
0065     const double basef = base;
0066     const double l = lmin + std::abs(i) / basef * (lmax - lmin);
0067     const double val = std::exp(l);
0068     if (i < 0)
0069       return -val;
0070     else
0071       return val;
0072   }
0073 
0074   /// reverse of pack8logClosed
0075   inline double unpack16logClosed(int16_t i, double lmin, double lmax, uint16_t base = 32768) {
0076     if (base > 32768)
0077       base = 32768;
0078     const double basef = base - 1;
0079     double l = lmin + std::abs(i) / basef * (lmax - lmin);
0080     if (std::abs(i) == base - 1)
0081       l = lmax;
0082     const double val = std::exp(l);
0083     if (i < 0)
0084       return -val;
0085     else
0086       return val;
0087   }
0088 
0089   inline int8_t pack8logCeil(double x, double lmin, double lmax, uint8_t base = 128) {
0090     if (base > 128)
0091       base = 128;
0092     const double l = std::log(std::abs(x));
0093     const double centered = (l - lmin) / (lmax - lmin) * base;
0094     int8_t r = std::ceil(centered);
0095     if (centered >= base - 1)
0096       r = base - 1;
0097     if (centered < 0)
0098       r = 0;
0099     if (x < 0)
0100       r = r == 0 ? -1 : -r;
0101     return r;
0102   }
0103 
0104   inline int8_t pack8log(double x, double lmin, double lmax, uint8_t base = 128) {
0105     if (base > 128)
0106       base = 128;
0107     const double l = std::log(std::abs(x));
0108     const double centered = (l - lmin) / (lmax - lmin) * base;
0109     int8_t r = centered;
0110     if (centered >= base - 1)
0111       r = base - 1;
0112     if (centered < 0)
0113       r = 0;
0114     if (x < 0)
0115       r = r == 0 ? -1 : -r;
0116     return r;
0117   }
0118 
0119   /// pack a value x distributed in [-1,1], with guarantee that -1 and 1 are preserved exactly in packing and unpacking.
0120   /// tries to keep the best precision for x close to the endpoints, sacrifying that in the middle
0121   inline int8_t pack8logClosed(double x, double lmin, double lmax, uint8_t base = 128) {
0122     if (base > 128)
0123       base = 128;
0124     const double l = std::log(std::abs(x));
0125     const double centered = (l - lmin) / (lmax - lmin) * (base - 1);
0126     int8_t r = round(centered);
0127     if (centered >= base - 1)
0128       r = base - 1;
0129     if (centered < 0)
0130       r = 0;
0131     if (x < 0)
0132       r = r == 0 ? -1 : -r;
0133     return r;
0134   }
0135 
0136   inline double unpack8log(int8_t i, double lmin, double lmax, uint8_t base = 128) {
0137     if (base > 128)
0138       base = 128;
0139     const double basef = base;
0140     const double l = lmin + std::abs(i) / basef * (lmax - lmin);
0141     const double val = std::exp(l);
0142     if (i < 0)
0143       return -val;
0144     else
0145       return val;
0146   }
0147 
0148   /// reverse of pack8logClosed
0149   inline double unpack8logClosed(int8_t i, double lmin, double lmax, uint8_t base = 128) {
0150     if (base > 128)
0151       base = 128;
0152     const double basef = base - 1;
0153     double l = lmin + std::abs(i) / basef * (lmax - lmin);
0154     if (std::abs(i) == base - 1)
0155       l = lmax;
0156     const double val = std::exp(l);
0157     if (i < 0)
0158       return -val;
0159     else
0160       return val;
0161   }
0162 
0163 }  // namespace logintpack
0164 #endif