用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迴圈語句之前宣告。