所以,简单的过程,计算一个阶乘数。代码如下。
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++大数库。
除了其他评论之外,我还想指出您的代码中的两个严重错误。
- 你对负数没有防备。 零
- 的阶乘是 1,而不是零。
是的,你达到了极限。根据定义,C++ 中的 int 是有符号的。而且,呃,不,C++从来没有想过。如果你告诉它做一件事,它就会去做,即使它显然是错误的。
考虑使用大数库。他们中的许多人都在C++。
如果未指定有符号或无符号,则默认为签名。您可以使用编译器上的命令行开关对其进行修改。
请记住,C(或C++)是一种非常低级的语言,并且完全按照您告诉它要做的事情。如果你告诉它把这个值存储在一个有符号的int中,这就是它要做的。 作为程序员,你必须弄清楚什么时候这是一个问题。这不是语言的工作。
我的Windows计算器(Start-Run-Calc)告诉我
hex (3813186000) = E34899D0
hex (-481781296) = FFFFFFFFE34899D0
所以是的,原因是签名的限制。由于阶乘根据定义只能是正数,并且只能针对正数进行计算,因此参数和返回值无论如何都应该是无符号数。(我知道每个人都使用 int i = 0
in for 循环,我也是。但撇开这一点不谈,如果值不能为负,我们应该始终使用无符号变量,这是 IMO 的好做法)。
阶乘的一般问题是,它们可以很容易地生成非常大的数字。您可以使用浮点数,从而牺牲精度,但避免整数溢出问题。
哦,等等,根据我上面写的,你应该把它做成一个未签名的浮点;-)
如果我记得不错的话:
无符号短 int = 最大值 65535
无符号整数 = 最大4294967295
无符号长 = 最大4294967295
无符号长长 (Int64 )= 最大18446744073709551615
编辑来源:
整数/长最大值
现代编译器变量