2017-10-07 45 views
1

我想学习一些C编程,并测试我的基本技能,我正在计算一个简单的计算因子。但是,不给出120的正确答案5的阶乘,它给出了-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; 
} 

在此先感谢!

+0

假装你是一台计算机,并尝试一步一步运行它,x = 2(或3)。或者,在调试器中运行它。 – user31264

+5

请参阅[**如何调试小程序**](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/)并与鸭子交谈...真的,它帮助':)' –

+1

作为提示:看看循环绑定。 – templatetypedef

回答

3

您的问题是功能factorial()正在不断修改x。对于初始为3或更多的x中的任何一个,x将继续增加,因此循环将继续运行。

请考虑如果您致电fact(3)

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

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

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

注意上面的模式.....结束条件是i < x。每个迭代中增加ix乘以i。这意味着xi确实增加得快得多,这意味着i < x总是如此。

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

最终x会溢出 - 将其乘以i的结果将产生超过可存储在int中的结果的结果。溢出int的结果是未定义的.....在这一点上可能发生任何事情。

将上面的描述与如果要求计算3的因子时应该执行的操作相比较。你会做类似的步骤吗?可能不会。

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

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

1

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

B)你还对每个循环x *= i增加X几乎成倍,您的循环将无法正常工作。

你可能已经注意到你得到一个负数。循环完全退出的原因是,您选择将x输入为32位有符号整数(默认为int) - 处理器以二进制方式工作:因此,一旦以高于仅32位的实际可能值进行工作,它仍然试图做数学,但它会丢失数据并回到负数。所以一旦x循环回去并成为负数,然后i > x和循环退出。

这里:http://tpcg.io/8sX5ls

+0

我不确定为什么您认为给定a)符号位/进位标志的基本性质,也不b)由用户输出证明。 –

+0

嘿嘿,我试图通过回答问题来获得我的老师徽章,但是它很难,因为总是有这么多其他答案XD –

1

的错误是在for,一个数的阶乘是N * N-1 * ... * N-(N-1),所以解决这个问题,仅仅以x - 1开始索引并将其减1,直到变为1,对不起我的英文不好,我希望你明白我的意思。

这里就是答案:

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

只是为了解释为什么负数,首先我们必须了解它被宣布为for会发生什么。

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

正如我们所看到的情况为它在循环继续为i < x,但在它被分配到xx * ix * = i or x = x * i)的值,所以x没有固定值,并且总是不断增加, i以小于x的速度增加,因为i总是添加到1(i ++, i + = 1 or i = i + 1),这导致x无法访问,则for将处于无限循环。

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

我们必须记住,一个数字以二进制形式表示在内存中,最后一个二进制数表示数字是正数还是负数,0表示正数,1表示负数,当发生整数溢出时,最后一个数字更改为1,使其如此消极。

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

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

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

+0

你能解释OPs代码导致的非常不利的结果吗? – Yunnosch

+0

老兄,答案很长,我不能把它放在这里,所以我编辑了我以前的答案,回答你的问题,好吧。 –

+0

这就是改善答案的意图。看起来你已经得到了赞赏。 – Yunnosch