71 #include <type_traits>
91 template <
typename QuantT,
typename MinT,
typename MaxT,
typename ValueT>
92 [[nodiscard]] QuantT
encode(MinT quant_min, MaxT quant_max, ValueT value) noexcept;
102 template <
typename ReturnT,
typename MinT,
typename MaxT,
typename ValueT>
103 [[nodiscard]] ReturnT
decode(MinT quant_min, MaxT quant_max, ValueT value) noexcept;
115 template <
typename QuantT,
typename ExtentT,
typename ValueT>
116 [[nodiscard]] QuantT
encode(ExtentT extent, ValueT value) noexcept;
128 template <
typename ReturnT,
typename ExtentT,
typename ValueT>
129 [[nodiscard]] ReturnT
decode(ExtentT extent, ValueT value) noexcept;
135 template <
typename QuantT,
typename MinT,
typename MaxT,
typename ValueT>
136 inline QuantT
encode(MinT quant_min, MaxT quant_max, ValueT value) noexcept {
137 static_assert(std::is_integral_v<QuantT> && !std::is_same_v<QuantT, bool>,
"QuantT must be integral.");
138 static_assert(std::is_arithmetic_v<MinT>,
"MinT must be arithmetic.");
139 static_assert(std::is_arithmetic_v<MaxT>,
"MaxT must be arithmetic.");
140 static_assert(std::is_arithmetic_v<ValueT>,
"ValueT must be arithmetic.");
142 using CalcT = std::common_type_t<float, MinT, MaxT, ValueT>;
144 auto min =
static_cast<CalcT
>(quant_min);
145 auto max =
static_cast<CalcT
>(quant_max);
146 auto target =
static_cast<CalcT
>(value);
148 if VUNLIKELY (!std::isfinite(min) || !std::isfinite(max) || std::isnan(target) || max <= min) {
149 return static_cast<QuantT
>(0);
152 auto quant_max_value =
static_cast<CalcT
>(std::numeric_limits<QuantT>::max());
153 auto quant_min_value =
154 std::is_signed_v<QuantT> ? -quant_max_value :
static_cast<CalcT
>(std::numeric_limits<QuantT>::lowest());
156 auto quant_lowest_value =
static_cast<CalcT
>(std::numeric_limits<QuantT>::lowest());
157 auto quant_range = quant_max_value - quant_min_value;
159 auto scaled = ((target - min) * quant_range / (max - min)) + quant_min_value;
162 auto scale = std::fmax(std::fabs(min), std::fabs(max));
163 auto ratio = ((target / scale) - (min / scale)) / ((max / scale) - (min / scale));
164 scaled = (ratio * quant_range) + quant_min_value;
167 auto rounded = scaled >=
static_cast<CalcT
>(0) ? scaled +
static_cast<CalcT
>(0.5) : scaled -
static_cast<CalcT
>(0.5);
170 return static_cast<QuantT
>(0);
173 if VUNLIKELY (rounded >= quant_max_value) {
174 return std::numeric_limits<QuantT>::max();
177 if VUNLIKELY (rounded <= quant_lowest_value) {
178 return std::numeric_limits<QuantT>::lowest();
181 return static_cast<QuantT
>(rounded);
184 template <
typename QuantT,
typename ExtentT,
typename ValueT>
185 inline QuantT
encode(ExtentT extent, ValueT value) noexcept {
186 static_assert(std::is_integral_v<QuantT> && std::is_signed_v<QuantT> && !std::is_same_v<QuantT, bool>,
187 "QuantT must be a signed integral type.");
188 static_assert(std::is_arithmetic_v<ExtentT>,
"ExtentT must be arithmetic.");
189 static_assert(std::is_arithmetic_v<ValueT>,
"ValueT must be arithmetic.");
191 using CalcT = std::common_type_t<float, ExtentT, ValueT>;
193 auto extent_value =
static_cast<CalcT
>(extent);
194 auto target =
static_cast<CalcT
>(value);
196 if VUNLIKELY (!std::isfinite(extent_value) || std::isnan(target) || extent_value <=
static_cast<CalcT
>(0)) {
197 return static_cast<QuantT
>(0);
200 auto quant_max_value =
static_cast<CalcT
>(std::numeric_limits<QuantT>::max());
201 auto quant_lowest_value =
static_cast<CalcT
>(std::numeric_limits<QuantT>::lowest());
202 auto scaled = target * quant_max_value / extent_value;
204 if VUNLIKELY (!std::isfinite(scaled) && std::isfinite(target)) {
205 scaled = (target / extent_value) * quant_max_value;
208 auto rounded = scaled >=
static_cast<CalcT
>(0) ? scaled +
static_cast<CalcT
>(0.5) : scaled -
static_cast<CalcT
>(0.5);
211 return static_cast<QuantT
>(0);
214 if VUNLIKELY (rounded >= quant_max_value) {
215 return std::numeric_limits<QuantT>::max();
218 if VUNLIKELY (rounded <= quant_lowest_value) {
219 return std::numeric_limits<QuantT>::lowest();
222 return static_cast<QuantT
>(rounded);
225 template <
typename ReturnT,
typename MinT,
typename MaxT,
typename ValueT>
226 inline ReturnT
decode(MinT quant_min, MaxT quant_max, ValueT value) noexcept {
227 static_assert(std::is_arithmetic_v<ReturnT>,
"ReturnT must be arithmetic.");
228 static_assert(std::is_arithmetic_v<MinT>,
"MinT must be arithmetic.");
229 static_assert(std::is_arithmetic_v<MaxT>,
"MaxT must be arithmetic.");
230 static_assert(std::is_integral_v<ValueT> && !std::is_same_v<ValueT, bool>,
"ValueT must be integral.");
232 using CalcT = std::common_type_t<float, ReturnT, MinT, MaxT>;
234 auto min =
static_cast<CalcT
>(quant_min);
235 auto max =
static_cast<CalcT
>(quant_max);
236 auto target =
static_cast<CalcT
>(value);
238 if VUNLIKELY (!std::isfinite(min) || !std::isfinite(max) || std::isnan(target) || max <= min) {
239 return static_cast<ReturnT
>(0);
242 auto quant_max_value =
static_cast<CalcT
>(std::numeric_limits<ValueT>::max());
243 auto quant_min_value =
244 std::is_signed_v<ValueT> ? -quant_max_value :
static_cast<CalcT
>(std::numeric_limits<ValueT>::lowest());
246 auto quant_lowest_value =
static_cast<CalcT
>(std::numeric_limits<ValueT>::lowest());
247 auto quant_range = quant_max_value - quant_min_value;
249 if VUNLIKELY (target >= quant_max_value) {
250 target = quant_max_value;
251 }
else if VUNLIKELY (target <= quant_lowest_value) {
252 target = quant_lowest_value;
255 auto decoded = ((target - quant_min_value) * (max - min) / quant_range) + min;
258 auto ratio = (target - quant_min_value) / quant_range;
259 auto scale = std::fmax(std::fabs(min), std::fabs(max));
260 auto normalized = ((
static_cast<CalcT
>(1) - ratio) * (min / scale)) + (ratio * (max / scale));
261 decoded = normalized * scale;
265 return static_cast<ReturnT
>(0);
268 if constexpr (std::is_integral_v<ReturnT>) {
269 auto return_max_value =
static_cast<CalcT
>(std::numeric_limits<ReturnT>::max());
270 auto return_lowest_value =
static_cast<CalcT
>(std::numeric_limits<ReturnT>::lowest());
272 if VUNLIKELY (decoded >= return_max_value) {
273 return std::numeric_limits<ReturnT>::max();
276 if VUNLIKELY (decoded <= return_lowest_value) {
277 return std::numeric_limits<ReturnT>::lowest();
281 return static_cast<ReturnT
>(decoded);
284 template <
typename ReturnT,
typename ExtentT,
typename ValueT>
285 inline ReturnT
decode(ExtentT extent, ValueT value) noexcept {
286 static_assert(std::is_arithmetic_v<ReturnT>,
"ReturnT must be arithmetic.");
287 static_assert(std::is_arithmetic_v<ExtentT>,
"ExtentT must be arithmetic.");
288 static_assert(std::is_integral_v<ValueT> && std::is_signed_v<ValueT> && !std::is_same_v<ValueT, bool>,
289 "ValueT must be a signed integral type.");
291 using CalcT = std::common_type_t<float, ReturnT, ExtentT, ValueT>;
293 auto extent_value =
static_cast<CalcT
>(extent);
295 if VUNLIKELY (!std::isfinite(extent_value) || extent_value <=
static_cast<CalcT
>(0)) {
296 return static_cast<ReturnT
>(0);
299 auto target =
static_cast<CalcT
>(value);
300 auto quant_max_value =
static_cast<CalcT
>(std::numeric_limits<ValueT>::max());
301 auto decoded = target * extent_value / quant_max_value;
304 decoded = (target / quant_max_value) * extent_value;
308 return static_cast<ReturnT
>(0);
311 if constexpr (std::is_integral_v<ReturnT>) {
312 auto return_max_value =
static_cast<CalcT
>(std::numeric_limits<ReturnT>::max());
313 auto return_lowest_value =
static_cast<CalcT
>(std::numeric_limits<ReturnT>::lowest());
315 if VUNLIKELY (decoded >= return_max_value) {
316 return std::numeric_limits<ReturnT>::max();
319 if VUNLIKELY (decoded <= return_lowest_value) {
320 return std::numeric_limits<ReturnT>::lowest();
324 return static_cast<ReturnT
>(decoded);
Cross-platform macros for visibility, branch hints, copy prevention, singletons and string helpers.
#define VUNLIKELY(...)
Short alias for VLINK_UNLIKELY.
Definition: macros.h:289
QuantT encode(MinT quant_min, MaxT quant_max, ValueT value) noexcept
Quantizes a value from a real range into an integral type.
Definition: quantize.h:136
ReturnT decode(MinT quant_min, MaxT quant_max, ValueT value) noexcept
Dequantizes an integral value into a real range.
Definition: quantize.h:226