为什么两个正整数的乘积是负整数?
Why is the product of two positive integers a negative integer?
这学期我上了系统编程课。
为什么 50000*50000 会是负数?
我试图理解这个逻辑。
这是幻灯片的屏幕截图
slide image
32 位带符号整数的存储方式是第 0-30 位作为数字,第 31 位表示数字的符号。
这意味着可以表示的最大值是2,147,483,647(0-30的所有位都已设置,第31位为0表示正数)。
50,000 和 50,000 的乘积是 25,000,000,000 大于这个数字,这就是所谓的溢出。这意味着数据从其预期边界(底部 31 位)到符号位有 "overflowed"。
您现在设置了第 31 位,表示这是一个负数。要从它的二进制表示中找出一个负数,你需要取补码(翻转所有位),加一,然后在它前面加上一个负号。
当你取个的补码时要小心,你将自己限制在 32 位范围内......你不应该包括高于位 31 的位。
查看 signed number representations 了解更多信息。
这是因为在大多数编程语言中,整数数据类型具有固定大小。
这意味着每个整数值都有定义的最小值和最大值。
例如,在 C# 中,INT 最大值为 2147483647,MIN 为 -2147483648
在 PHP 32 位中是 2147483647 和 -2147483648
在 PHP 64 位中是 9223372036854775807 和 -9223372036854775808
当您尝试超过该值时会发生什么?只是计算机会使所谓的整数溢出,并且该值将循环回到最小值。
换句话说,在 C# 中 2147483647 + 1 = -2147483648(假设您使用整数数据类型,而不是长整数或浮点数)。这正是 50000 * 50000 发生的情况,它只是超过最大值并从下一个值开始循环。
确切的最小值和最大值取决于所使用的语言、构建代码的平台、代码所在的平台 运行 以及值的静态类型。
希望它能帮您解决所有问题!
示例程序伪代码
Print --> ("Size of int: " + (Integer.SIZE/8) + " bytes.");
int a=50000;
int b=50000;
Print --> (" Product of a and b " + a*b);
Output :
Size of int: 4 bytes.
Product of a and b:-1794967296
分析:
4字节= 4*8= 32bits.
由于signed int可以保存负值,一位用于符号(-或+),因此可用于数字范围的位数=31。
数字范围 = -(2^31) , 0 和 (2^31-1)
[为0牺牲一个正数]
-2147483648, 0 和 2147483647
最大可能的正整数 = 2147483647(大于 1600000000,所以 40000*40000 可以)
实际产品50000*50000=2500000000(大于2147483647)
在实践中,许多可移植的 C 程序假设有符号整数溢出使用二进制补码算法可靠地回绕。
然而 C 标准说程序行为在溢出时是未定义的,并且在少数情况下 C 程序不能在一些现代实现上工作,因为它们的溢出没有像他们的作者预期的那样环绕。
http://www.gnu.org/software/autoconf/manual/autoconf-2.62/html_node/Integer-Overflow.html
这学期我上了系统编程课。 为什么 50000*50000 会是负数? 我试图理解这个逻辑。 这是幻灯片的屏幕截图
slide image
32 位带符号整数的存储方式是第 0-30 位作为数字,第 31 位表示数字的符号。
这意味着可以表示的最大值是2,147,483,647(0-30的所有位都已设置,第31位为0表示正数)。
50,000 和 50,000 的乘积是 25,000,000,000 大于这个数字,这就是所谓的溢出。这意味着数据从其预期边界(底部 31 位)到符号位有 "overflowed"。
您现在设置了第 31 位,表示这是一个负数。要从它的二进制表示中找出一个负数,你需要取补码(翻转所有位),加一,然后在它前面加上一个负号。
当你取个的补码时要小心,你将自己限制在 32 位范围内......你不应该包括高于位 31 的位。
查看 signed number representations 了解更多信息。
这是因为在大多数编程语言中,整数数据类型具有固定大小。
这意味着每个整数值都有定义的最小值和最大值。
例如,在 C# 中,INT 最大值为 2147483647,MIN 为 -2147483648 在 PHP 32 位中是 2147483647 和 -2147483648 在 PHP 64 位中是 9223372036854775807 和 -9223372036854775808
当您尝试超过该值时会发生什么?只是计算机会使所谓的整数溢出,并且该值将循环回到最小值。
换句话说,在 C# 中 2147483647 + 1 = -2147483648(假设您使用整数数据类型,而不是长整数或浮点数)。这正是 50000 * 50000 发生的情况,它只是超过最大值并从下一个值开始循环。
确切的最小值和最大值取决于所使用的语言、构建代码的平台、代码所在的平台 运行 以及值的静态类型。
希望它能帮您解决所有问题!
示例程序伪代码
Print --> ("Size of int: " + (Integer.SIZE/8) + " bytes.");
int a=50000;
int b=50000;
Print --> (" Product of a and b " + a*b);
Output :
Size of int: 4 bytes.
Product of a and b:-1794967296
分析: 4字节= 4*8= 32bits.
由于signed int可以保存负值,一位用于符号(-或+),因此可用于数字范围的位数=31。 数字范围 = -(2^31) , 0 和 (2^31-1) [为0牺牲一个正数]
-2147483648, 0 和 2147483647
最大可能的正整数 = 2147483647(大于 1600000000,所以 40000*40000 可以) 实际产品50000*50000=2500000000(大于2147483647)
在实践中,许多可移植的 C 程序假设有符号整数溢出使用二进制补码算法可靠地回绕。 然而 C 标准说程序行为在溢出时是未定义的,并且在少数情况下 C 程序不能在一些现代实现上工作,因为它们的溢出没有像他们的作者预期的那样环绕。 http://www.gnu.org/software/autoconf/manual/autoconf-2.62/html_node/Integer-Overflow.html