2014-01-30 27 views
2

我用這個編譯器編譯這個代碼。對於號碼我寫18446744073709551615(2^64-1)。 Pelles的可執行文件顯示「18446744073709551615是主要」,但GCC的可執行文件顯示「18446744073709551615不是主要」。爲什麼結果不同?Pelles C和GCC用這個C素數測試給出了不同的結果

#include <stdio.h> 
#include <math.h> 
int main(void) 
{ 
    unsigned long long number; 
    printf("number: "); 
    scanf("%llu",&number); 
    unsigned long trsq=truncl(sqrtl(number)); 
    char s=1; 
    for(unsigned long i=2;i<=trsq;i++) { 
     if (number%i==0) { 
      s=0; 
      break; 
     } 
    } 
    if (s==1) { 
     printf("%llu is prime\n",number); 
    } else { 
     printf("%llu isn't prime\n",number); 
    } 
    return 0; 
} 

編輯:

我測試和gcc得到12,pellesÇ給8用於sizeof(長雙)。

+3

對於它的價值,GCC是正確的,因爲例如數量顯然不是素數 - 它至少整除5比1,確認它的確不是素數較大的一些其他號碼:HTTP:// WWW。 wolframalpha.com/input/?i=is+18446744073709551615+prime – CmdrMoozy

+5

Pelles說:*警告#2215:從「無符號長長整型」到「長雙」的轉換;可能丟失數據*和*警告#2215:從'long double'轉換爲'unsigned long int';可能會丟失數據。*因此存在您的問題。如果你硬編碼值:*#警告2072:溢出中恆「18446744073709551615」 * – this

+0

@CmdrMoozy沒有,我得到8 –

回答

3

許多事情在C語言的定義中沒有說明,包括數字類型的大小以及在溢出或精度丟失的情況下會發生什麼。因此,當您不檢查數字類型範圍或使用浮點時,通常會獲得不同的實現(不同的編譯器,不同的硬件,不同的操作系統)的不同結果。

鑑於self.twocomments提供的信息,這裏是對發生了什麼似是而非的解釋。我沒有Pelles C檢查。

Pelles警告:

警告#2215:從 '無符號長長整型' 到 '長雙' 的轉換;可能會丟失數據。 警告#2215:從'long double'轉換爲'unsigned long int';數據

猜想#1的可能損失:數學值2^64-1不能在一個long double精確表示(這是可能的,如2^64-1需要尾數的64位,幾個實現具有許多)。它被舍入到2^64,可以完全表示。

number的值是2^64-1,它是unsigned long long。由於函數sqrtl需要參數long double,因此該值將轉換爲該類型。鑑於猜想#1,sqrtl的值爲2^64。結果是2^32。由於這是一個整數,所以truncl返回相同的值。

猜想#2:unsigned long是32位類型(這在32位機器上非常普遍,在64位版本的Windows上也是如此,至少在Microsoft編譯器中)。

如果unsigned long是32位類型,那麼值2^32將溢出它。 C標準沒有定義從浮點值到整數值的轉換溢出的情況,編譯器可以選擇做他們想做的任何事情。猜想#3:在Pelles C中,當一個浮點數值被轉換爲一個整數類型時,它將以類型的大小進行模數化,就像轉換爲一個較小的整數類型時發生的情況一樣。

在猜想#3,試圖分配值2^32至trsq,這是unsigned long類型和32位寬的,它設置爲0。因此trsq具有值0時,for循環運行0次,並且程序錯誤地報告該數字是主要的。

一個簡單的解決辦法是將trsq更改爲unsigned long long

請注意,如果程序的最大素數因子非常接近其平方根(例如,如果數字是素數的平方),那麼程序可能會報告一些數字,因爲將number轉換爲浮點值可能會將其舍入,因此trsq可能最終小於平方根,甚至小於小於平方根的最大整數。

您可以通過執行integer square root computation避免這一切的麻煩。

相關問題