numeric_limits<long>::min() 的 C++11 abs();

C++11 abs() of numeric_limits<long>::min();

我运行关注以下

test.cpp

#include <iostream>
#include <limits>
#include <cstdlib>
using namespace std;

int main(int argc, char** argv) {
    long value = numeric_limits<long>::min();
    value = abs(value);
    cout << value << endl;
}

根据我编译的计算机和 运行 程序,我得到不同的结果。

要么我得到:

abs(numeric_limits<long>::min())

或者我得到:

numeric_limits<long>::min()

在后一种情况下,似乎没有执行 abs() 。我想知道是什么导致了这种差异以及我应该如何适应它。我应该以不同的方式计算 abs() 吗?

在 2 的补码(大多数现代芯片使用的整数表示法)中,负值总是比正值多 1 - 例如signed char 在大多数实现中从 -128 运行到 127。如果你这样做,你期望得到什么 -((signed char)-128) 给定 127 是一个有符号字符可以表示的最大正数?

您的 (signed) long 也有类似的问题,即 -(most negative long) 不可表示并且会发生溢出。 signed 整数的溢出是未定义的,所以你得到一个奇怪的结果也就不足为奇了

你会得到负数的原因是计算机读取有符号数的方式,即二进制补码。如果数字类型包含 4 位,则此类型的边界数字可能是 0111 = 7 和 1000 = -8。当您使用 abs() 函数时,它会翻转位,然后将负数加一以使它们变为正数。当你这样做到最小数量时,你会得到 1000 => 翻转位 => 0111 => 添加一个 => 1000 这是相同的数字。

查看 std::abs 的参考资料告诉我们出了什么问题:

Computes the absolute value of an integer number. The behavior is undefined if the result cannot be represented by the return type.

所以任何事情都有可能发生。它甚至在下面解释了对有符号整数使用 2 的补码的系统的情况:

Notes

In 2's complement systems, the absolute value of the most-negative value is out of range, e.g. for 32-bit 2's complement type int, INT_MIN is -2147483648, but the would-be result 2147483648 is greater than INT_MAX, which is 2147483647.

如果您对 C99/C11 standard 的实际标准引用感兴趣,请参见第 7.20.6/7.22.6 节,因为 C++ 仅引用 [=11= 中函数的 C 标准](有一些额外的重载)。