【问题标题】:When I calculate a large factorial, why do I get a negative number?当我计算一个大的阶乘时,为什么我得到一个负数?
【发布时间】:2008-10-25 12:38:28
【问题描述】:

所以,简单的程序,计算一个阶乘数。代码如下。

int calcFactorial(int num)
{
    int total = 1;

    if (num == 0)
    {
        return 0;
    }

    for (num; num > 0; num--)
    {
        total *= num;
    }

    return total;
}

现在,对于大多数数字来说,这工作得很好而且很花哨(当然有更快、更优雅的解决方案,但这对我有用)。但是,当输入更大的数字(例如 250)时,坦率地说,就是废话。现在,250 的前几个阶乘“位”是 { 250, 62250, 15126750, 15438000, 3813186000 } 以供参考。

我的代码吐出 { 250, 62250, 15126750, 15438000, -481781296 } 这显然是关闭的。我的第一个怀疑可能是我违反了 32 位整数的限制,但鉴于 2^32 是 4294967296,我不这么认为。我唯一能想到的可能是它违反了 signed 32 位限制,但它不应该能够考虑这种事情吗?如果签名是问题,我可以通过使整数无符号来解决这个问题,但这只是一个临时解决方案,因为下一次迭代产生 938043756000,这远远高于 4294967296 的限制。

那么,我的问题是签名限制吗?如果是这样,我能做些什么来计算大数(虽然我有一个“LargeInteger”类我之前做了一个可能适合的!)而不会再次遇到这个问题?

【问题讨论】:

  • 一句话总结:溢出.

标签: c++ signed factorial


【解决方案1】:

2^32 没有给你有符号整数的限制。

有符号整数限制实际上是2147483647(如果您使用 MS 工具在 Windows 上进行开发,其他工具套件/平台可能会有自己的限制,可能类似)。

您需要一个 C++ 大数库 like this one

【讨论】:

  • 对于好奇的人来说,这个数字 (2,147,483,647) 是 2^31 - 1。无符号整数的限制是 2^32 - 1。
【解决方案2】:

除了其他 cmets,我想指出您的代码中的两个严重错误。

  • 您对负数毫无防备。
  • 零的阶乘是一,而不是零。

【讨论】:

  • 我忘记了 0! = 1,但正如 Treb 所说,根据定义,阶乘是非负数。但是,一个错误!
【解决方案3】:

是的,你达到了极限。根据定义,C++ 中的 int 是有符号的。而且,呃,不,C++ 永远不会思考。如果你告诉它做一件事,它就会做,即使它显然是错误的。

考虑使用大量库。对于 C++,其中有很多。

【讨论】:

  • 哈哈! “C++ 永远不会思考。”很好的答案!
【解决方案4】:

如果不指定有符号或无符号,则默认为有符号。您可以使用编译器上的命令行开关来修改它。

请记住,C(或 C++)是一种非常低级的语言,并且完全按照您的要求执行。如果你告诉它把这个值存储在一个有符号的 int 中,它就会这样做。 作为程序员必须弄清楚什么时候会出现问题。这不是语言的工作。

【讨论】:

    【解决方案5】:

    我的 Windows 计算器(Start-Run-Calc)告诉我

    hex (3813186000) =         E34899D0
    hex (-481781296) = FFFFFFFFE34899D0
    

    所以是的,原因是签名限制。由于阶乘在定义上只能是正数,并且只能为正数计算,因此参数和返回值都应该是无符号数。 (我知道每个人都在 for 循环中使用 int i = 0,我也是。但抛开这一点,如果值不能为负,我们应该始终使用无符号变量,这是 IMO 的好习惯。

    阶乘的普遍问题是,它们很容易生成非常大的数字。您可以使用浮点数,从而牺牲精度但避免整数溢出问题。

    哦等等,根据我上面写的,你应该把它设为一个无符号浮点数;-)

    【讨论】:

      【解决方案6】:

      如果我没记错的话:

      无符号短整数 = 最大值 65535

      无符号整数 = 最大值 4294967295

      无符号长 = 最大值 4294967295

      unsigned long long (Int64)= max 18446744073709551615

      编辑来源:

      Int/Long Max values

      Modern Compiler Variable

      【讨论】:

      • 在大多数现代编译器中,int 与 long 相同。
      • long long 是 MSDN 文档中的 INT64。我的价值观也适用于现代编译器。祝你有美好的一天
      • 对不起,这是完全错误的。请始终参考您正在使用的 CPU 架构的编译器文档。你甚至不适合 Visual C++:msdn.microsoft.com/en-us/library/s3f49ktz(VS.80).aspx
      • @Daok:我上次检查(10 年前)时,'int' 是 32 位。 :) 请记住,标准规定 sizeof(int) >= 2 和 sizeof(int)
      • 您甚至没有阅读自己的参考资料。 home.att.net/~jackklein/c/inttypes.html#int谁是对的?在任何给定的编译器上,一个或另一个可能是正确的。在某些编译器上,两者都是错误的。我知道一个用于 24 位 DSP 的编译器,其中 int 有 24 位。
      猜你喜欢
      • 2023-02-25
      • 2016-09-19
      • 2013-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-16
      • 1970-01-01
      相关资源
      最近更新 更多