1

我做了一个应用程序来解析阶乘,当我为变量输入一个超过 20 位的数字时long,它返回一个负数。我想知道为什么longC# 中的变量在越界时返回负值?它应该是这样的吗?

4

8 回答 8

11

这是非常正常的行为,称为溢出。

第一步,把它变成一个错误

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

您可以看到最高有效位(最左侧)用作+/-符号。

于 2012-10-02T18:52:59.647 回答
4

每个人都已经提到了为什么它会变成负数,所以我只会告诉你如何改变你的阶乘函数。使用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);
    }
}
于 2012-10-02T18:59:37.427 回答
3

根据文档

保存有符号的 64 位(8 字节)整数,值范围从 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 (9.2...E+18)。

20! = 2.432902e+18
21! = 5.1090942e+19

如您所见,21!远远超过 hte max on long

C# 数据类型的一些更好的链接:

整数类型 浮点类型

如果您计划计算超过 20! 的阶乘,则需要升级到浮点类型。

于 2012-10-02T18:54:42.390 回答
1

是的,21!比长期限制要好,但是 20!不是。因此它是溢出的。

于 2012-10-02T18:52:46.057 回答
1

c# 中的所有数字类型都支持 max 函数,因此Long.MaxValue会告诉您限制。至于为什么它变成负数,这与设置二进制补码编码数的高位有关

于 2012-10-02T18:53:37.717 回答
1

它被称为算术溢出

一个 4 位示例:

 1101
+0101
-----
10010

如您所见,正确答案需要 5 位,但我们如何将其存储为 4 位?!我们不能正确,溢出必须发生。

要回答您的直接问题,您的值会变为负数,因为它是有符号的,因此当它溢出时会环绕到下限。

于 2012-10-02T18:57:01.903 回答
1

long数据类型有一个MSDN参考。基本上你告诉我们的并不是全部。这个长期上限是9.223372037x10^1820 的阶乘2.432902008x10^18小于 的上限long

我会发布一些代码,以便我们查看实际发生的情况。

于 2012-10-02T18:57:41.040 回答
1

如果您不想要那种溢出,请考虑使用BigInteger. 要使用它,您的 C# 项目需要包含对 .NET 程序集的引用System.Numerics.dll。你的代码文件应该包括

using System.Numerics;

前几名。

于 2012-10-02T18:59:43.723 回答