我做了一个应用程序来解析阶乘,当我为变量输入一个超过 20 位的数字时long
,它返回一个负数。我想知道为什么long
C# 中的变量在越界时返回负值?它应该是这样的吗?
8 回答
这是非常正常的行为,称为溢出。
第一步,把它变成一个错误
checked
{
// your calculations
}
这本书对所有的位和字节都有详尽的解释。
这可能有助于弄清楚:
static void Main2(string[] args)
{
short s = 0;
Console.WriteLine("Dec: {0,6} Hex {0:X4}", s);
s -= 1;
Console.WriteLine("Dec: {0,6} Hex {0:X4}", s);
s = short.MaxValue;
Console.WriteLine("Dec: {0,6} Hex {0:X4}", s);
s += 1;
Console.WriteLine("Dec: {0,6} Hex {0:X4}", s);
Console.WriteLine(s == short.MinValue); // is MaxValue+1 == MinValue ?
}
它打印
Dec: 0 Hex 0000
Dec: -1 Hex FFFF
Dec: 32767 Hex 7FFF
Dec: -32768 Hex 8000
True
将十六进制字符读取为位:
0 = 0000
1 = 0001
7 = 0111
8 = 1000
F = 1111
您可以看到最高有效位(最左侧)用作+/-
符号。
每个人都已经提到了为什么它会变成负数,所以我只会告诉你如何改变你的阶乘函数。使用BigInteger(假设您使用的是 .NET 4.0)。
static BigInteger Factorial(BigInteger bigInt) {
if (bigInt == 0) {
return 0;
}
else if (bigInt == 1) {
return 1;
}
else {
return bigInt * Factorial(bigInt - 1);
}
}
是的,21!比长期限制要好,但是 20!不是。因此它是溢出的。
c# 中的所有数字类型都支持 max 函数,因此Long.MaxValue会告诉您限制。至于为什么它变成负数,这与设置二进制补码编码数的高位有关
它被称为算术溢出。
一个 4 位示例:
1101
+0101
-----
10010
如您所见,正确答案需要 5 位,但我们如何将其存储为 4 位?!我们不能正确,溢出必须发生。
要回答您的直接问题,您的值会变为负数,因为它是有符号的,因此当它溢出时会环绕到下限。
long
数据类型有一个MSDN参考。基本上你告诉我们的并不是全部。这个长期上限是9.223372037x10^18
20 的阶乘2.432902008x10^18
小于 的上限long
。
我会发布一些代码,以便我们查看实际发生的情况。
如果您不想要那种溢出,请考虑使用BigInteger
. 要使用它,您的 C# 项目需要包含对 .NET 程序集的引用System.Numerics.dll
。你的代码文件应该包括
using System.Numerics;
前几名。