为什么INT_MAX减INT_MIN等于 -1

Why INT_MAX minus INT_MIN equals -1?

本文关键字:INT 等于 MIN MAX 为什么      更新时间:2023-10-16

正如此页面所建议的,INT_MAX = 32767INT_MIN = -32767,因此INT_MAX - INT_MIN应该等于65534,但是它给了我-1;

我很困惑,因为 65534 不会在 C++ 中溢出 int 的限制,即使我在长整型中分配值,它仍然给了我 -1。我想可能是我误解了关于C++减少的一些机制。有人不知道INT_MAX减去INT_MIN时到底发生了什么?提前感谢!

INT_MAX 仅在

int类型实际上是 16 位宽的编译器上时才等于 32767。如今,在嵌入式处理器的编译器中仍然可以看到这样的INT_MAX值。

无论INT_MAX是什么,它既是 int 类型的,也是该类型的最大值。如果在int类型中,从最正的值中减去最负的int值,则会触发溢出,这是未定义的行为

无论您的int是16位宽还是64位,都没有关系;根据ISO C,INT_MAX - INT_MIN表示的计算没有明确定义的含义。

-1 结果可能由您的实现定义。 也就是说,编译器遵守有关整数溢出的特定规则。查看您的编译器手册。

如果类型比 int 宽,则可以执行减法。例如,假设long long比某个给定编译器上的int宽。(这不是必需的,但假设我们有一个实现,这是真的,这很常见(。然后我们可以做:

(long long) INT_MAX - (long long) INT_MIN

现在没有溢出,因为计算是在更广泛的类型中执行的。我们得到算术上正确的值。当然,该值不适合类型 int


现在关于 -1 的假设,请记住它可能只是一个侥幸,根本不是由编译器定义的。

假设您有一个用于二进制补码机的编译器,该编译器将签名溢出的行为定义为具有简单的"包装"语义。然后,-1 值可以解释如下。假设INT_MIN是最负的二进制补码值,以二进制表示1000..0000INT_MAX0111..1111.然后计算INT_MAX - INT_MIN减去这两个。 在较低的位中没有太多有趣的事情发生,因为0序列正在从1序列中减去。然后,减法达到上位:0 - 1 。 这导致值1,借出("借"是减法与加法的"进位"对应的(。借款被丢弃,我们只剩下截断的结果1111...1111. 这当然是两者的补码表示 -1。

注意INT_MIN也可以简单地定义为-INT_MAX,这是二进制值1000...0001。在这种情况下,相同的包装算法将产生结果 -2,也许比 -1 更令人惊讶。

所以为什么你看到 -1 可能是你得到了 2 的补码包装行为,再加上 INT_MIN 实际上并不是 INT_MAX 的算术逆(这将需要 -2 结果(,而是一个比这少 1 的值。

如果你说INT_MAX = 32767某些实现,当然甚至是32768溢出。

除了请注意,如果您要添加两个整数文字,即使您将该结果分配给long,也要说int + int(假设long可以保存该添加的结果(,这无济于事,因为当int添加int时可能会发生溢出 - 因为添加的结果不适合int;在这种情况下,编译器不会将int提升为long,基于以下事实加法的结果不适合int.

INT_MAX = 32767

且 INT_MIN = -32767

实际上它们是:

-

32767 (-2^15+1( 或更少*

32767 (2^15-1( 或更高版本*

我几乎在你的系统上,sizeof(int(==4 -> 4 字节 -> 32 位。

INT_MAX定义为 2^32-1 == 4294967295。

对INT_MIN应用相同。

键入 smth,例如:

std::cout << INT_MAX << " " << INT_MIN << std::endl;

你会看到的。int(INT_MAX-INT_MIN 中实际上有一个溢出,所以它是 -1

该页面没有说任何此类内容。它说INT_MAX至少是32767。它并没有说它是平等的。如果您想知道特定实现的实际价值,请将其打印出来(或查看该实现的文档,请记住它可能取决于目标体系结构(。

反正INT_MAX的定义是int的最大值,所以INT_MAX+1就足以溢出int的极限了,别说INT_MAX - INT_MIN了。您获得的-1值是特定于实现的行为,但这不是典型 2 补码实现的意外结果,其中 INT_MAX 等于 2N-1-1,INT_MIN 等于 -2N-1,对于某些值 N,称为以位为单位的int的"宽度"。这是最常见的[*] 32,但标准允许低至16。因此,对于具有 32 位 2 补码int的实现,实际值是2147483647-2147483648的,对于具有 16 位 2 补码int的实现,实际值是32767-32768

在这样的实现中,假设整数溢出环绕,那么INT_MAX - INT_MIN的结果将如您所见-1,因为数学值为 2 N-1,即 -1 模 2N例如,GCC 有一个选项-fwrapv如果你想确保整数溢出换行,你可以使用它,如果你不指定该选项,那么它可能会换行,或者它可能会做一些不同的事情。

[*] 通过一些非常不科学的"最常见"概念。