繁体   English   中英

从无符号整数值生成有符号整数值并返回

[英]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

有趣的是,您不需要这些函数保留ab的值。 这很好,因为如果是这样,那么它们将无法实施。

因此,您希望在转换时“抵消”这些值。

所以int(0)变成unsigned(std::numeric_limits<int>::max()+1)unsigned(0)变成std::numeric_limits<int>::min()

有了它和 Maxim 的结构,您应该能够编写您需要的函数。

哦,如果你使用INT_MININT_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.

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