[英]Make signed int value from unsigned int value and back
我需要将无符号整数序列转换为有符号整数序列并保持元素的顺序。
理想情况下,我需要这样的功能
template <typename T>
std::make_signed_t<T> MakeSigned(T val);
template <typename T>
std::make_unsigned_t<T> MakeUnsigned(T val);
实施它们的正确方法是什么?
编辑1:
函数 MakeSigned 和 MakeUnsigned 应满足以下条件:
对于给定的一对参数 a、b 和返回值 a1、b1,如果 a <= b 则 a1 <= b1。
并且对于给定的签名
MakeSigned(MakeUnsigned(a)) == a
编辑2 :
MakeSigned 这样做(对于给定的类型 uint8_t、uint16_t、uint32_t、uint64_t):
0 => INT_MIN
UINT_MAX => INT_MAX
MakeUnsigned:
INT_MIN => 0
INT_MAX => UINT_MAX
一种解决方案是在映射到/ unsigned
类型时减去/添加偏差项std::numeric_limits<Signed>::min()
。 必须使用无符号算术进行计算,该算术包装不会产生未定义的行为:
#include <iostream>
#include <type_traits>
#include <limits>
#include <cstdint>
template<typename T>
typename std::enable_if_t<std::is_unsigned_v<T>, std::make_signed<T>>::type map_to_signed(T val) {
using U = std::make_signed_t<T>;
return val + std::numeric_limits<U>::min(); // Wrapping unsigned addition.
}
template<typename T>
typename std::enable_if_t<std::is_signed_v<T>, std::make_unsigned<T>>::type map_to_unsigned(T val) {
using U = std::make_unsigned_t<T>;
return static_cast<U>(val) - std::numeric_limits<T>::min(); // Wrapping unsigned subtraction.
}
int main() {
std::cout << map_to_signed(0u) << '\n';
std::cout << map_to_unsigned(map_to_signed(0u)) << "\n\n";
std::cout << std::numeric_limits<int>::max() << '\n';
std::cout << map_to_unsigned(std::numeric_limits<int>::max()) << '\n';
std::cout << map_to_signed(map_to_unsigned(std::numeric_limits<int>::max())) << "\n\n";
std::cout << std::numeric_limits<unsigned>::max() << '\n';
std::cout << map_to_signed(std::numeric_limits<unsigned>::max()) << '\n';
std::cout << map_to_unsigned(map_to_signed(std::numeric_limits<unsigned>::max())) << "\n\n";
std::cout << std::numeric_limits<uint64_t>::max() << '\n';
std::cout << map_to_signed(std::numeric_limits<uint64_t>::max()) << '\n';
std::cout << map_to_unsigned(map_to_signed(std::numeric_limits<uint64_t>::max())) << "\n\n";
}
输出:
-2147483648
0
2147483647
4294967295
2147483647
4294967295
2147483647
4294967295
18446744073709551615
9223372036854775807
18446744073709551615
有趣的是,您不需要这些函数保留a
和b
的值。 这很好,因为如果是这样,那么它们将无法实施。
因此,您希望在转换时“抵消”这些值。
所以int(0)
变成unsigned(std::numeric_limits<int>::max()+1)
, unsigned(0)
变成std::numeric_limits<int>::min()
有了它和 Maxim 的结构,您应该能够编写您需要的函数。
哦,如果你使用INT_MIN
和INT_MAX
而不是numeric_limits
,你就会失败。
我会简单地翻转符号位:
template <typename T>
std::make_signed_t<T> MakeSigned(T val)
{
return val ^ (1u << (sizeof(T) * 8 - 1));
}
template <typename T>
std::make_unsigned_t<T> MakeUnsigned(T val)
{
return val ^ (1u << (sizeof(T) * 8 - 1));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.