简体   繁体   English

在 uint32_t 范围内变换 uint64_t 范围

[英]Transform uint64_t range in uint32_t range

I want transform an uint64_t into an uintw_t with w in { 8, 16, 32} preserving "range":我想将 uint64_t 转换为 uintw_t,其中 w in { 8, 16, 32} 保留“范围”:

#include <cstdint>
#include <type_traits>

Idea 1:想法1:

f:[a,b]->[c,d] with f(a)=c, f(b)=d f:[a,b]->[c,d] 与 f(a)=c, f(b)=d

let a = 0, b = 2^64-1, c = 0 and d = 2^w-1.让 a = 0, b = 2^64-1, c = 0 和 d = 2^w-1。

if f(x) = mx+n with m = (dc)/(ba) = (2^w-1)/(2^64-1) < 1 (we need float or double...), n = 0如果 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;
}

Don't work with uint16_t :c.不要使用 uint16_t :c。

*Idea 2: *想法2:

Don't work correctly, i wrongly tested it with 0xffffffffffffffffull...不能正常工作,我用 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);
}

It cuts the number to its lower bits.它将数字削减到较低的位。

Idea 3:想法3:

Group bytes and remap with idea 1. For example 0xabcabcab in uint32_t to uint16_t:将字节分组并使用想法 1 重新映射。例如 uint32_t 中的 0xabcabcab 到 uint16_t:

abca -> [x] cabc -> [y] with ffff--> ff and 0000--> 00 abca -> [x] cabc -> [y] with ffff--> ff and 0000--> 00

Idea 4:想法4:

Right shift (CHAR_BIT = 8...)右移 (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;
}

This idea makes the most sense to me, however it rules out the effect of minor bits without any weighting or rounding.这个想法对我来说最有意义,但是它排除了没有任何加权或舍入的次要位的影响。

https://quick-bench.com/q/Vs1W4UP35MCpJo5pY1ebXnM7QNo https://quick-bench.com/q/Vs1W4UP35MCpJo5pY1ebXnM7QNo

In "real usage" double and shift versions are equivalent for uint32_t In "individual use without context" shift version is faster for uint32_t在“实际使用”中,double 和 shift 版本对于 uint32_t 是等效的 在“没有上下文的单独使用”中,uint32_t 的 shift 版本更快

My main question would be, what is the most usual in this type of conversions?我的主要问题是,这种类型的转换中最常见的是什么?

As an additional question, is there any efficient way to perform this process with some kind of rounding?作为一个附加问题,是否有任何有效的方法可以通过某种舍入来执行此过程?

Shifting is standard;变速是标准的; you can get some simple rounding by first adding half of the least-significant preserved bit's value before shifting, although that doesn't implement proper round-to-even and you have to worry about overflow.您可以通过在移位之前首先添加最低有效位的值的一半来获得一些简单的舍入,尽管这没有实现正确的舍入到偶数,您必须担心溢出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM