为什么 Int32.MaxValue * Int32.MaxValue 等于 1?

5
我知道,Int32.MaxValue * Int32.MaxValue 会产生一个比Int32更大的数字;但是,这个语句不应该引发某种异常吗?
当我做类似于IF (X * Y > Z)的事情时,其中所有内容都是Int32。如果X和Y足够大,则从X * Y中得到一个虚假值。
为什么会这样,如何解决这个问题?除了将所有内容转换为Int64之外,还有什么方法可以解决这个问题?

这是否在unchecked块中? - Skywalker
请参见 https://dev59.com/T3E95IYBdhLWcg3wUMPW。 - Ian Mercer
6个回答

26

因为int32将结果限制在32位以内。

因此,如果你以字节级别查看数学运算。

FFFFFFFF * FFFFFFFF = FFFFFFFE00000001

正如您所看到的,最低的4个字节等于1。


19

默认情况下,C# 算术运算在未经检查的上下文中完成,这意味着数值将会循环。

您可以使用 "checked" 和 "unchecked" 关键字来控制此行为。(参考链接)


刚遇到一个情况,int.maxvalue + 1 等于 int.minvalue...我一直在想这个问题,直到意识到它一定是溢出了! - richard

8

有趣的是,无论您使用什么进制,这都有效:

(n-1)*(n-1)  mod n 
n^2 - 2n + 1 mod n
0   -  0 + 1 mod n
           1 mod n

6

您需要请求它:

checked {
    int a = int.MaxValue;
    int b = int.MaxValue;
    int c = a * b;    // kaboom
}

6

您已在项目中禁用了溢出检查。如果开启了检查模式,它将抛出异常。


谢谢您的回复!我没有禁用溢出检查;在Visual Studio中,这个设置在哪里? - Greg Balajewicz
我这里没有VS的副本,但如果我没记错的话,它应该在高级编译器选项中(右键单击项目,然后属性->生成->高级) - munissor

2

Int32.MaxValue(使用此处给出的值)为2,147,483,647。

在二进制中,它是:111 1111 1111 1111 1111 1111 1111 1111...2^31-1。第一位是符号位。

如果你将这个数乘以自己,你会得到:11 1111 1111 1111 1111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0001

回到最初的问题“为什么是1?”,因为Integer.MaxValue是最大值,所以会导致整数溢出。结果被截断为最低的31位,即全为0加1。

编辑:这里有一个关于二进制乘法的教程。以全1的简单情况为例:

111 * 111

你会得到:

00111 01110 + 11100 = 100001

你可以将其扩展为Int32.MaxValue的情况。为了简洁起见,我将其缩短为3个数字。

另外,正如另一个答案所说,在C#中这些溢出默认会发生。


一个对需要它的人来说是很好的处理方法,但是原帖的作者想知道为什么C#没有捕获并抛出错误。 - BCS

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