[英]Transform uint64_t range in uint32_t range
我想将 uint64_t 转换为 uintw_t,其中 w in { 8, 16, 32} 保留“范围”:
#include <cstdint>
#include <type_traits>
想法1:
f:[a,b]->[c,d] 与 f(a)=c, f(b)=d
让 a = 0, b = 2^64-1, c = 0 和 d = 2^w-1。
如果 f(x) = mx+n 且 m = (dc)/(ba) = (2^w-1)/(2^64-1) < 1(我们需要 float 或 double...),n = 0
template<typename T, typename std::enable_if< std::is_unsigned_v <T>, T>::type = 0>
T transform_a(uint64_t n)
{
constexpr double factor = static_cast<double>(~T(0)) / ~uint64_t(0);
return static_cast<T>( factor*n );
}
template<>
uint64_t transform_a(uint64_t n)
{
return n;
}
不要使用 uint16_t :c。
*想法2:
不能正常工作,我用 0xffffffffffffffffull 错误地测试了它...
template<typename T, typename std::enable_if< std::is_unsigned_v <T>, T>::type = 0>
T transform_b(uint64_t n)
{
return static_cast<T>(n);
}
它将数字削减到较低的位。
想法3:
将字节分组并使用想法 1 重新映射。例如 uint32_t 中的 0xabcabcab 到 uint16_t:
abca -> [x] cabc -> [y] with ffff--> ff and 0000--> 00
想法4:
右移 (CHAR_BIT = 8...)
template<typename T, typename std::enable_if< std::is_unsigned_v <T>, T>::type = 0>
T transform_c(uint64_t n)
{
return static_cast<T>(n>>(64 - 8*sizeof(T)));
}
template<>
uint64_t transform_c(uint64_t n)
{
return n;
}
这个想法对我来说最有意义,但是它排除了没有任何加权或舍入的次要位的影响。
https://quick-bench.com/q/Vs1W4UP35MCpJo5pY1ebXnM7QNo
在“实际使用”中,double 和 shift 版本对于 uint32_t 是等效的 在“没有上下文的单独使用”中,uint32_t 的 shift 版本更快
我的主要问题是,这种类型的转换中最常见的是什么?
作为一个附加问题,是否有任何有效的方法可以通过某种舍入来执行此过程?
变速是标准的; 您可以通过在移位之前首先添加最低有效位的值的一半来获得一些简单的舍入,尽管这没有实现正确的舍入到偶数,您必须担心溢出。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.