[英]Simple C++ factorial program
作为家庭作业,我需要一个读取非负整数的程序,并计算并打印其阶乘。 到目前为止我编写了代码,但如果我尝试输入50! 结果为0.它适用于较小的数字。 任何帮助将非常感激。
#include <iostream>
using namespace std;
int main()
{
int counter = 1;
int number;
cout << "Please enter a number: ";
cin >> number;
int factorial = number;
while (counter != number)
{
factorial = factorial * (number - counter);
counter++;
}
cout << "The factorial of " << number << "! is: " << factorial << endl;
return 0;
}
50!
是30414093201713378043612608166064768844377641568960512000000000000
,对于一个int来说太大了。 由于整数溢出,结果为0。
如果要计算大因子,则需要使用一些BigInteger类。 看看这个: 线程
已经有了一些答案。 然而,他们都缺乏提供一些(imho)重要事实:
无论您选择多大的结果类型,您的程序将能够计算的内容总是有限制的。
在正常的口袋计算器69! 是他们可以显示的最大因子(因为它是具有两位数指数的最大因子)。 要求更大的东西只会导致错误或NaN。 实际上这完全没问题,因为在实践中你很少需要具有完美精度的巨大因子。 通常可以使用Stirlings近似或使用其他技巧来避免冗长的计算(顺便说一下69!对于袖珍计算器来说也是一个不错的基准,因为它可能在慢速计算器上花费几秒钟)。
结论 :对于合理的输入,您的代码非常好。 如果你真的需要寻求更高的阶乘,有办法,但我想你的任务并不是真的要求它。 而且,无论你怎么做,你总是达到极限。 因此,为了使您的代码“无bug”,我会添加类似的东西
assert(number < 50 && "Sorry, this number is too big");
在计算之前。
选择较大范围的数据类型,不超过存储在变量'factorial'中的值
你应该声明它, **long long int factorial = number ;**
现在,它显示为零,因为int(此处为signed)因此对于将int数据类型存储为2byte的系统,其范围从-32568到+32567。 在修饰符“long long”的帮助下,实际上将其存储字节增加到8字节,从而产生更大的范围。
现在,如果要存储在任何变量中的值超出其范围,则它通过开始从最小范围(这里是-32568)存储的值来执行循环旋转。
而你也可以使用**unsigned long long int factorial = number ;**
甚至可以使它的范围更大。 由于无符号将计算其负范围与正范围,从而导致更大的正范围。
在类或结构中尝试双或长数据类型。 您还必须相应地修改您的代码。
Factorial只会产生疯狂的大数字。 您可以尝试更广泛或可能更宽的数据类型(如long
),但这只会推迟问题。 它会在某些时候失败。 也许在51!
,也许是60!
。 我们甚至不谈1000!
。 这就是阶乘的本质。
当然,专门的大数字图书馆可以大大缓解这个问题。 但他们不是初学者的东西。
但是,您可以做的就是安全地找出您的程序是否达到计算机的限制,如果是这种情况则打印错误消息。 C ++提供了一种名为std::numeric_limits
的机制,它告诉您数据类型可以表示的最大可能值。
这是一个基于您的代码的简单示例:
#include <iostream>
#include <limits> // needed for std::numeric_limits
using namespace std;
int main()
{
int counter = 1;
int number;
cout << "Please enter a number: ";
cin >> number;
int factorial = number;
while (counter != number)
{
if (std::numeric_limits<int>::max() / factorial < (number - counter)) {
std::cout << "cannot handle such large numbers\n";
return 0;
}
factorial = factorial * (number - counter);
counter++;
}
cout << "The factorial of " << number << "! is: " << factorial << endl;
return 0;
}
一旦检测到错误条件,将会发生什么并不重要,而是如何检测它:
std::numeric_limits<int>::max() / factorial < (number - counter)
这可以防止整数溢出。 它在数学上等同于:
std::numeric_limits<int>::max() < factorial * (number - counter) // wrong!
但是,后一版本显然不起作用,因为factorial * (number - counter)
可能已经产生溢出。 通过将右侧的乘法转换为左侧的除法,您可以优雅地避免该问题。
顺便说一句,如果用户输入一个非常大的数字,所有这些仍然没有好处。 因此,您应该在使用number
之前检查std::cin
的状态,如果输入无法解释为int
,则同样打印错误消息。 这使您的程序更加健壮。 如果有人输入大数字,它不会简单地崩溃或产生无意义的结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.