【问题标题】:Factorial program in C is wrong after 20 [duplicate]C中的阶乘程序在20之后是错误的[重复]
【发布时间】:2016-03-09 23:34:33
【问题描述】:

它一直工作到 20,但如果输入 21,它会返回 1419745... 当 21 阶乘实际上是 51090942171709440000。我假设这是因为无符号长最大值,但是这个错误的数字在哪里(141.. .) 来自,我怎样才能让程序计算出更大数字的阶乘?

#include <stdio.h>

unsigned long fact(unsigned long input);

int main()

{

    int input;

    printf("Enter an integer to find the factorial of: ");
    scanf(" %d", &input);

    printf("The Factorial of %d = %lu\n" , input, fact(input)); 

    return 0;
}

unsigned long fact(unsigned long input)
{
    if (input == 0)
            return 1;
    else    
        return input * fact(input - 1);
}

【问题讨论】:

  • 您系统上的ULONG_MAX 是什么?
  • 乘法溢出后,通常会留下最低有效部分,但它是二进制截断,而不是十进制截断,这就是该值看起来不合理的原因。有两种方法:使用大型 int 库,或者有时需要乘积的模数 - 通过在每次乘法后应用模数来将数字保持在限制范围内。
  • @CoolGuy long long 不必超过 64 位。在 OP 的计算机上,long 已经是 64 位了。另一方面,int 在任何系统上都不应超过 32 位。
  • @CoolGuy 事实上,这并不完全正确:unsigned long 应该是至少 32 位,unsigned long long 应该是至少 64 位和sizeof(unsigned long long) &gt;= sizeof(unsigned long)。所以unsigned long longunsigned long 具有相同的大小并存储相同的值并非不可能
  • 各种整数类型的数值限制是学习任何编程语言时最先讨论的问题之一。这通常在任何编程语言的初学者级编程书籍的第 1 章或第 2 章中讨论。

标签: c long-integer unsigned factorial


【解决方案1】:

这只能回答你一半的问题(为什么会这样)。

你得到的结果是21! mod 2^64。这是因为您使用的是 64 位系统,而21! 大于可以存储为 64 位无符号整数的最大数。

您为大于或等于21 的值计算的所有阶乘都是错误的;它们不能用 64 位整数表示,因为它们比这更长。

您可以尝试使用unsigned long long作为函数fact()返回的值的类型(并将%llu改成printf()格式字符串%lu);它可能会有所帮助,但这取决于某些因素。例如,它对我的​​架构没有帮助。

您可以通过检查sizeof(unsigned long long) 返回的值来了解它是否可以帮助您。如果 if 是8,那么你就不走运了。 20 是您可以在该系统上计算阶乘的最大数字。


如果您的目的是计算阶乘,那么您必须使用知道如何处理大数的库。但是,如果您需要阶乘来进行其他计算(例如,combinations),那么您可以尝试避免生成大数并找到一种方法来匹配每个乘法与除法。这样你使用的数字的大小在 64 位整数的限制之间,你可以比21 走得更远。

或者您可以使用double 来代替整数,这样您就可以重新开始工作,但会失去精度。大浮点数正确存储数字的大小及其第一位数字。最后一位数字丢失。

我最近没怎么用 C/C++ 编程,我不能向你推荐一个可以帮助你进行大量计算的库:-(

【讨论】:

    【解决方案2】:

    数字来自溢出。无符号算术是模(该类型的最大值)完成的,所以一点数学应该可以解释为什么你会得到你所做的结果。

    有符号整数溢出的结果是未定义的,因此如果您一直使用有符号整数,您可能会得到任何东西(尽管在很多系统上它可能完全相同)

    【讨论】:

      猜你喜欢
      • 2018-10-22
      • 2021-11-13
      • 2020-12-13
      • 1970-01-01
      • 2013-08-04
      • 1970-01-01
      • 2019-05-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多