简单的 C++ 阶乘程序

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 class。 看看这个:Thread

尝试在 class 或结构中使用 double 或 long 数据类型。您还必须相应地修改您的代码。

选择不超过变量'factorial'

中存储的值的更大范围的数据类型

您应该将其声明为,**long long int factorial = number ;**

现在,它显示为零,因为 int(这里有符号)所以对于将 int 数据类型存储为 2byte 的系统,它的范围从 -32568 到 +32567。 在修饰符 "long long" 的帮助下,您实际上将其存储字节增加到 8 个字节,从而导致更大的范围。

现在,如果要存储在任何变量中的值超出其范围,那么它将通过从最小范围(此处为 -32568)开始存储的值来执行循环旋转。

而且您还可以使用 , **unsigned long long int factorial = number ;** 甚至使其范围更大。由于 unsigned 将计算其负范围和正范围,这会导致更大的正范围。

已经有一些答案了。然而,他们都没有提供一些(恕我直言)重要的事实:

无论您选择多大的结果类型,您的程序能够计算的内容总是有限的。

在普通袖珍计算器上 69!是他们可以显示的最大阶乘(因为它是具有两位数指数的最大阶乘)。要求任何更大的东西只会导致错误或 NaN。实际上这很好,因为在实践中你很少需要如此大的精确度如此大的阶乘。通常可以使用斯特林近似或使用其他技巧来避免冗长的计算(顺便说一句,69!也是袖珍计算器的一个很好的基准,因为在较慢的计算器上它可能已经花费了几秒钟)。

结论:您的代码非常适合合理的输入。如果你真的需要更高的阶乘,有很多方法,但我想你的作业并没有真正要求它。而且,无论你怎么做,你总是会遇到一个极限。因此,为了使您的代码 "bug free" 我会添加类似

的内容
assert(number < 50 && "Sorry, this number is too big");

计算前。

阶乘只会产生非常大的数字。您可以尝试使用更宽或可能更宽的数据类型(如 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,同样会打印一条错误消息。这使您的程序更加健壮。如果有人输入大数字,它不会简单地崩溃或产生无意义的结果。