当我计算一个大因子时,为什么我得到一个负数?

时间:2008-10-25 12:38:28

标签: c++ signed factorial

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

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,我不这么认为。我唯一能想到的可能是它违反了签名 32位限制,但它不应该考虑这种事情吗?如果签名是问题我可以通过使整数无符号来解决这个问题,但这只是一个临时解决方案,因为下一次迭代产生938043756000,远高于4294967296限制。

那么,我的问题是签名限制吗?如果是这样,我可以做些什么来计算大数字(虽然我之前做过的“大型英语”课程可能很适合!)而不会再遇到这个问题?

7 个答案:

答案 0 :(得分:21)

2 ^ 32不会为您提供有符号整数的限制。

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

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

答案 1 :(得分:13)

除了其他评论之外,我还想指出代码中的两个严重错误。

  • 你无法防范负数。
  • 零因子是一,而不是零。

答案 2 :(得分:9)

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

考虑使用大量库。 C ++中有很多它们。

答案 3 :(得分:4)

如果未指定signed或unsigned,则默认为signed。您可以使用编译器上的命令行开关对其进行修改。

请记住,C(或C ++)是一种非常低级的语言,并准确你告诉它做什么。如果你告诉它将这个值存储在一个signed int中,那就是它将要做的。 ,程序员必须弄明白这是什么问题。这不是语言的工作。

答案 4 :(得分:1)

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

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

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

阶乘的一般问题是,他们可以轻松生成非常大数。您可以使用浮点数,从而牺牲精度但避免整数溢出问题。

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

答案 5 :(得分:1)

你有一个溢出问题。因子很容易超过整数的极限。您可以更改您的功能以返回双打,但这只会给您带来更多空间。在应用程序中,通常需要乘以非常小的阶乘倍数,其中最终结果将适合双精度但中间步骤不适合。这是一篇解释如何处理这种情况的文章:http://www.johndcook.com/blog/2008/04/24/how-to-calculate-binomial-probabilities/

答案 6 :(得分:-2)

如果我记得很清楚:

unsigned short int = max 65535

unsigned int = max 4294967295

unsigned long = max 4294967295

unsigned long long(Int64)= max 18446744073709551615

已编辑的来源:

Int/Long Max values

Modern Compiler Variable