1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
#ifndef liblogintpack_h
#define liblogintpack_h
#include <cmath>
#include <cstdint>
namespace logintpack {
constexpr int8_t smallestPositive = 0;
// note that abs(unpack(smallestNegative)) == unpack(1), i.e. there
// is no "x" such that "unpack(x) == -unpack(0)"
constexpr int8_t smallestNegative = -1;
inline int16_t pack16logCeil(double x, double lmin, double lmax, uint16_t base = 32768) {
if (base > 32768)
base = 32768;
const double l = std::log(std::abs(x));
const double centered = (l - lmin) / (lmax - lmin) * base;
int16_t r = std::ceil(centered);
if (centered >= base - 1)
r = base - 1;
if (centered < 0)
r = 0;
if (x < 0)
r = r == 0 ? -1 : -r;
return r;
}
inline int16_t pack16log(double x, double lmin, double lmax, uint16_t base = 32768) {
if (base > 32768)
base = 32768;
const float delta = (log(1. + exp((lmax - lmin) / base)) - log(2.)) * base / (lmax - lmin);
const double l = std::log(std::abs(x));
const double centered = (l - lmin) / (lmax - lmin) * base;
int16_t r = std::floor(centered);
if (centered - r > delta)
r += 1;
if (centered >= base - 1)
r = base - 1;
if (centered < 0)
r = 0;
if (x < 0)
r = r == 0 ? -1 : -r;
return r;
}
/// pack a value x distributed in [-1,1], with guarantee that -1 and 1 are preserved exactly in packing and unpacking.
/// tries to keep the best precision for x close to the endpoints, sacrifying that in the middle
inline int16_t pack16logClosed(double x, double lmin, double lmax, uint16_t base = 32768) {
if (base > 32768)
base = 32768;
const double l = std::log(std::abs(x));
const double centered = (l - lmin) / (lmax - lmin) * (base - 1);
int16_t r = round(centered);
if (centered >= base - 1)
r = base - 1;
if (centered < 0)
r = 0;
if (x < 0)
r = r == 0 ? -1 : -r;
return r;
}
inline double unpack16log(int16_t i, double lmin, double lmax, uint16_t base = 32768) {
if (base > 32768)
base = 32768;
const double basef = base;
const double l = lmin + std::abs(i) / basef * (lmax - lmin);
const double val = std::exp(l);
if (i < 0)
return -val;
else
return val;
}
/// reverse of pack8logClosed
inline double unpack16logClosed(int16_t i, double lmin, double lmax, uint16_t base = 32768) {
if (base > 32768)
base = 32768;
const double basef = base - 1;
double l = lmin + std::abs(i) / basef * (lmax - lmin);
if (std::abs(i) == base - 1)
l = lmax;
const double val = std::exp(l);
if (i < 0)
return -val;
else
return val;
}
inline int8_t pack8logCeil(double x, double lmin, double lmax, uint8_t base = 128) {
if (base > 128)
base = 128;
const double l = std::log(std::abs(x));
const double centered = (l - lmin) / (lmax - lmin) * base;
int8_t r = std::ceil(centered);
if (centered >= base - 1)
r = base - 1;
if (centered < 0)
r = 0;
if (x < 0)
r = r == 0 ? -1 : -r;
return r;
}
inline int8_t pack8log(double x, double lmin, double lmax, uint8_t base = 128) {
if (base > 128)
base = 128;
const double l = std::log(std::abs(x));
const double centered = (l - lmin) / (lmax - lmin) * base;
int8_t r = centered;
if (centered >= base - 1)
r = base - 1;
if (centered < 0)
r = 0;
if (x < 0)
r = r == 0 ? -1 : -r;
return r;
}
/// pack a value x distributed in [-1,1], with guarantee that -1 and 1 are preserved exactly in packing and unpacking.
/// tries to keep the best precision for x close to the endpoints, sacrifying that in the middle
inline int8_t pack8logClosed(double x, double lmin, double lmax, uint8_t base = 128) {
if (base > 128)
base = 128;
const double l = std::log(std::abs(x));
const double centered = (l - lmin) / (lmax - lmin) * (base - 1);
int8_t r = round(centered);
if (centered >= base - 1)
r = base - 1;
if (centered < 0)
r = 0;
if (x < 0)
r = r == 0 ? -1 : -r;
return r;
}
inline double unpack8log(int8_t i, double lmin, double lmax, uint8_t base = 128) {
if (base > 128)
base = 128;
const double basef = base;
const double l = lmin + std::abs(i) / basef * (lmax - lmin);
const double val = std::exp(l);
if (i < 0)
return -val;
else
return val;
}
/// reverse of pack8logClosed
inline double unpack8logClosed(int8_t i, double lmin, double lmax, uint8_t base = 128) {
if (base > 128)
base = 128;
const double basef = base - 1;
double l = lmin + std::abs(i) / basef * (lmax - lmin);
if (std::abs(i) == base - 1)
l = lmax;
const double val = std::exp(l);
if (i < 0)
return -val;
else
return val;
}
} // namespace logintpack
#endif
|