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

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 限制。

那么,我的问题是签名限制吗?如果是这样,我该怎么做才能计算大数(尽管我不久前制作了一个可能适合的“LargeInteger”类!)而不会再次遇到这个问题?

有帮助吗?

解决方案

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

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

您需要一个C ++大号库喜欢这个

其他提示

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

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

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

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

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

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

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

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

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

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

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

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

如果我记得很清楚:

unsigned short int = max 65535

unsigned int = max 4294967295

unsigned long = max 4294967295

unsigned long long(Int64)= max 18446744073709551615

已编辑的来源:

Int / Long Max值

现代编译器变量

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top