用C语言计算1~20的阶乘之和

  昨天(2018/12/7)在做C语言的课后练习题的时候,有一道题要求我们计算1~20的阶乘之和。代码很快就写出来了,考虑到结果的值会比较大,而在Windows操作系统下,int 类型和 long 类型居然都是4个字节(C#中long类型是八个字节,找同学试了下,Linux下C语言的long类型好像也是八个字节),所以我使用double类型。代码如下:

 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     double n = 1, sum = 0;
 6     for (int i = 1; i <= 20; i++)
 7     {
 8         n *= i;
 9         sum += n;
10     }
11     printf("%lf",sum);
12 }

结果输出了:2561327494111820300.000000

  我以为我得到了正确的结果,但我将同样的算法搬到C#中之后,却好像不是那么回事。(考虑到C#中long类型是八个字节,范围足够大,所以在C#中我直接使用了long类型。)代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Homework
 8 {
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             long n = 1, sum = 0;
14             for (int i = 1; i <= 20; ++i)
15             {
16                 n *= i;
17                 sum += n;
18             }
19             Console.WriteLine(sum);20             Console.ReadKey();
21         }
22     }
23 }

得到的结果是:2561327494111820313

  相差了13?什么鬼?我不(ji)厌(qi)其(wu)烦(liao)的按着计算器(科学计算器里有求阶乘的函数),得到的结果和我在C#里得到的一模一样。那C得出来的是什么鬼(其实在C#里将long改成double,得出来的好像也有误差)。而且我尝试着在输出结果之前,手动把sum加上了13,即在输出之前加入这么一条语句“sum += 13;”,发现……并没有什么用,结果还是 2561327494111820300.000000。那……加100?没用!加200?没用!加300?神奇的事情发生了,得到了 2561327494111820800.000000!???等下,这不是加了500麽,我只给它加了300。。。哭笑不得。

  对于具体原因我没有搞懂,可能是浮点数在计算机里的存储和计算有关吧,可能造成了舍入误差。反正就是数据类型的问题。

  那在Windows环境下用C语言做这道题,还得用 long long 类型。于是乎,C语言的代码变成了:

 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     long long n = 1, sum = 0;
 6     for (int i = 1; i <= 20; i++)
 7     {
 8         n *= i;
 9         sum += n;
10     }
11     printf("%I64d",sum);
12 }

输出说明符是“%I64d”,百度来的。总之结果是对了:2561327494111820313。

  所以,您也别纠结网上有的回答 2561327494111820300 得到了200+赞,却同时得到了600+踩了。至于得到结果 268040729 的,要么是int类型溢出(Windows操作系统下C语言的 long 类型也会溢出),要麽是结果输出的时候用了“%d”格式说明符导致溢出。

PS:long long 数据类型好像是C99标准增加的,而VC++6.0(别问我为什么说到这个东西)是在C99之前出现的东西,所以以上代码在VC++6.0里并不能使用。另外,VC++6.0也不支持“for (int i = 1; i <= 20; i++)”这种写法,变量 i 的声明得在for循环语句之前声明。

猜你喜欢

转载自www.cnblogs.com/Luquan/p/10088319.html