因此,简单的程序,计算一个阶乘数。代码如下。
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限制。
那么,我的问题是签名限制吗?如果是这样,我可以做些什么来计算大数字(虽然我之前做过的“大型英语”课程可能很适合!)而不会再遇到这个问题?
答案 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