2014-01-30 28 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避免这一切的麻烦。

相关问题