int left = std::numeric_limits<int>::min();
int right = -1;
//the code below instead of give one more than int_max gives: 18446744071562067968
unsigned long long result = left * right;
我尝试查找 UAC,但即使根据 UAC 规则,这也应该产生正确的输出。任何想法为什么结果不正确?
int left = std::numeric_limits<int>::min();
int right = -1;
//the code below instead of give one more than int_max gives: 18446744071562067968
unsigned long long result = left * right;
我尝试查找 UAC,但即使根据 UAC 规则,这也应该产生正确的输出。任何想法为什么结果不正确?
两个操作数都是int
,所以算术是在int
类型内执行的;运算结果超出 的范围int
,因此结果未定义。
要获得您期望的结果,请将一个操作数转换为long long
第一个:
unsigned long long result = left * (long long) right;
这仍然是潜在的未定义行为;尽早转换为无符号算术更安全(因为无符号算术包装并且不会溢出):
unsigned long long result = left * (unsigned long long) right;
请注意,您得出的结果是0xffffffff80000000
;这表明操作的实际结果std::numeric_limits<int>::min()
在int
类型中,然后对其进行符号扩展并强制转换为unsigned long long
.
将有符号 2 的补码的最小值乘以int
-1 是未定义的行为,因为结果超出了类型的范围。
在这种情况下,您的输出与 -2147483648 的结果一致,即溢出似乎已经环绕。您不能依赖有符号类型的环绕,只能依赖无符号类型。
将计算结果分配给unsigned long long
不会改变执行计算的类型。只要你做乘法,你就输了。因此,在乘法unsigned long long
之前将其中一个操作数转换为。
原因是乘法是根据 提交的int
。
两个参数都是int
,所以乘法给出了一个int
agein,你是对的,它给出了int_max
+ 1 ,相当于int_min
=-2147483648。所以它实际上是 -2147483648,但是对于 unsigned long long 它相当于 18446744071562067968,请参见十六进制代码:
int_min = 80000000
(unsigned long long) (int min) = ffffffff80000000