为什么这个阶乘计算不正确?

Why doesn't this factorial compute correctly?

我正在尝试学习一些 C 编程,并且为了测试我的基本技能,我正在编写一个计算阶乘的简单程序。但是,它没有给出 5 的阶乘的正确答案 120,而是给出了 -1899959296。怎么了?下面是我的代码:

#include <stdio.h>

int factorial(int x)
{
    int i;
    for(i=1; i < x; i++)
        x *= i;
    return x;
}

int main() 
{ 
    int a = 5, b;
    b = factorial(a);
    printf("The factorial of %d is %d \n", a, b);
    return 0;
}

提前致谢!

    int factorial(int x)
    {
        int i;
        int count =x;
        for(i=1; i < count ; i++)
            x *= i;
        return x;
    }

这样修改。你的问题是循环计数。由于 x 的值正在改变循环可能会变成无限的..

您的问题是函数 factorial() 不断修改 x。对于任何初始为 3 或更多的 xx 将不断增加,因此循环将保持 运行。

如果你打电话给fact(3)考虑一下。

使用 x = 3 调用该函数。使用 i = 1 的循环的第一次迭代会将 x 乘以 1。所以 x 的值仍然是 3ii会递增到2,小于3,所以开始下一次迭代

循环的第二次迭代将 x 乘以 2,得到 6 的结果。 i增加到3,小于6,所以下一次迭代开始。

第三次迭代将 x 乘以 3,得到 18 的结果。 i增加到4,小于18,所以下一次迭代开始。

注意上面的模式.....结束条件是i < xi 在每次迭代中递增。 x 乘以 i。这意味着 xi 增长得快得多......这意味着 i < x 总是正确的。

好吧几乎.....最终逻辑崩溃了。

最终 x 会溢出 - 将其乘以 i 的结果将超过 int 中可以存储的结果。 int 溢出的结果是未定义的..... 那时任何事情都可能发生。

比较上面的描述和如果被要求计算 3 的阶乘你会怎么做。你会做类似的步骤吗?可能不是。

C) 您正在使用 x 作为 for 循环的上限 i < x

B) 你还在每个循环中几乎以指数方式增加 x x *= i,你的循环将不起作用。

您可能已经注意到您得到了一个负数。循环完全退出的原因是您选择将 x 键入为 32 位带符号整数(默认值 int)- 处理器以二进制工作:因此一旦您超出实际可能的 32位,它仍然尝试进行数学运算,但它丢失了数据并循环回到负数。因此,一旦 x 返回并变为负值,然后 i > x 并且循环退出。

此处:http://tpcg.io/8sX5ls

错误在for,一个数的阶乘是n * n-1 * ... * n-(n-1),所以要解决这个问题,只需从 x - 1 开始索引并将其递减直到它变为 1,抱歉我的英语不好,我希望你能理解我说的。

这里是答案:

for ( i = x - 1; i > 1; --i )
        x *= i;

只是为了解释为什么是负数,首先我们必须了解它被声明的 for 中发生了什么。

for(i=1; i < x; i++)
        x *= i;

我们可以看到它在循环中继续的条件是i < x,但在它内部分配给x x * i的值(x * = i or x = x * i ), 所以 x 没有常数值并且一直在增加, i 以比 x 小的速度增加,因为 i 总是加 1 (i ++, i + = 1 or i = i + 1),导致x不可达,那么for就会死循环。

但是每个类型都有它的范围,int 是 4 个字节,因此是 32 位,会发生什么时候 x 超出这个范围就会出现著名的整数溢出,这这就是为什么它的值为负,然后 for 的条件变为假,然后 for 停止。

我们要记住,一个数在内存中是以二进制形式表示的,最后一个二进制数就是表示这个数是正数还是负数,0为正数,1为负数,最后一个整数溢出时number 变为 1 ,使其变为负值。

为了更好地理解这一点,这里有一些可以提供帮助的链接:

https://en.wikipedia.org/wiki/Two%27s_complement

https://en.wikipedia.org/wiki/Integer_overflow.