将有符号整数范围映射到无符号整数

6
我面临一个问题,需要将有符号整数转换为无符号整数,保留它们的范围和顺序。
给定以下定义:
#include <limits>

#define MIN(X) std::numeric_limits<X>::min();
#define MAX(X) std::numeric_limits<X>::max();

如何最快且正确地将有符号整数类型 T 的范围 [MIN(T), MAX(T)] 映射到无符号整数类型 U 的范围 [0, MAX(U)]?
其中: - T 是一个有符号整数类型 - U 是一个无符号整数类型 - sizeof(T) == sizeof(U)
我尝试了各种位操作和数字方法来解决这个问题,但都没有成功。

1
我遇到了一个问题,即有符号整数应该转换为无符号整数,同时保留它们的范围。那么,你期望-1变成什么呢?你是想保留范围但不保留实际值吗?另外,哪些“各种方法”对你没有起作用?它们为什么没能成功?(在这种情况下,“未成功”是什么意思?)请就具体方法提出具体问题。 - Lightness Races in Orbit
如果保留范围,就能保留值,因为值是由其在范围内的位置定义的。如果您阅读问题,显然是关于范围转换的,其中-MAX(T)变为0。因此,-1变为MAX(U)/2 - 1。 - plasmacel
@plasmacel 我建议您编辑您的问题,以澄清最后一条评论中的意图。通常,将ABC映射到XYZ可以通过例如A->X,B->Z,C->Y来满足。 - M.M
你似乎也假定了二进制补码表示法(否则范围大小将不相等) - M.M
为什么不直接转换为无符号数?位模式将始终保留。 - phuclv
请看如下链接,了解在 C++ 中将无符号整数映射到有符号整数的方法:http://stackoverflow.com/questions/37123682/c-mapping-unsigned-integer-ranges-to-signed - andrew cooke
1个回答

10
unsigned int signedToUnsigned(signed int s) {
  unsigned int u =  1U + std::numeric_limits<int>::max();
  u += s;
  return u;
}

查看实例

这将向signed int添加signed_max + 1以确保将[MIN(int), MAX(int)]映射到[0, MAX(unsigned int)]


为什么这个答案会有效并正确映射:

当您将有符号整数与无符号整数相加时,有符号数将提升为无符号类型。来自第4.7节[conv.integral]

 

如果目标类型是无符号的,则结果值是与源整数同余的最小无符号整数(模2 n ,其中n是用于表示无符号类型的位数)。   [注意:在二进制补码表示中,此转换是概念性的,并且没有改变位模式(如果没有截断)。 -注]


2
优秀的解释,引用了标准。 - namezero
1
确实,这正是我想要的! - plasmacel
1
@plasmacel,由于您的问题涉及到任意整数类型,因此我将简单地说一下,使用适当的std::make_unsigned和一些创造性的SFINAE技巧,也可以将其作为通用模板来实现。 - WhozCraig
更准确地说,[conv.prom] 表示 intunsigned int 都会被提升为 long(假设 longint 更长)进行加法运算,然后根据 [conv.integral] 的规则将结果转换回 unsigned int。(或者... +=+ 的工作方式不同吗?) - user1084944

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接