2012-03-26 84 views
3

我',尝试这个简单的代码。它示出了第一10个整数,不能在浮法来表示:(浮动)铸造不起作用

int main(){ 
    int i, cont=0; 
    float f; 
    double di, df; 
    for(i=10000000, f=i; i<INT_MAX; i++, f=i, df=f, di=((float)i)){ 
    if(i!=f){ 
     printf("i=%d f=%.2f df=%.2lf di=%.2lf\n", i, f, df, di); 
     if(cont++==10) return 0; 
    } 
    } 
    return 1; 
} 

是双变量,但我将其设置为(浮点)我,所以它应该是等于DF,但不是这样。

例如,数16777217被表示为16777216˚FDF,但仍然是16777217,忽略(浮点)铸造。

这怎么可能?

**我用这:海湾合作委员会(Ubuntu的4.4.3-4ubuntu5)4.4.3

+1

什么平台和编译器版本? – sarnold 2012-03-26 22:27:29

+3

为什么你使用这样的逗号运算符?绝对没有必要,并增加了不必要的复杂问题。 – Joe 2012-03-26 22:28:10

+0

你不需要说'%lf'。只是'%f'很好,而且它意味着'double'。 – 2012-03-26 22:29:40

回答

2

有关您的问题是6.3.1.8:2在the C99 standard

浮动的值表达式的操作数和浮点数的结果可以以比该类型所需的 更高的精度和范围来表示;类型不会因此而改变。

并且特别脚注52:

铸造和赋值操作符仍然需要如6.3.1.4和6.3.1.5描述,以进行他们的指定的转换。

阅读脚注,我会说你已经在编译器中发现了一个错误。

您可能已经在您的编译器中发现了两个错误:i!=f比较在浮动块之间完成(请参阅标准的同一页上的促销规则),所以它应始终为false。尽管在后一种情况下,我认为编译器可能允许使用更大的类型进行6.3.1.8:2的比较,可能会使得比较等效于(double)i!=(double)f,因此有时也是如此。段6.3.1.8:2是我最讨厌的标准中的段落,我仍然试图理解严格的别名。

+0

非常感谢。我认为你是对的,并且在编译器中存在一个bug(或特征?),因为我!= f在双精度而不是浮点数之间进行比较。 – salteador 2012-03-26 23:11:32

+0

这是gcc中一个非常长期的已知bug,开发人员几乎无法解决,因为它会适度地损害不关心正确性的人的性能。如果你不关心让你的程序与旧的cpus不兼容,你可以用'-msse'来解决这个问题(使用SSE而不是FPU作为浮点)。请注意,在x86以外的平台(也许是m68k?)上,这个问题不存在。 – 2012-03-27 03:07:51

+0

@R:如果他们想要最大化性能而不考虑正确性,为什么不简单地让所有的浮点运算返回42.0?这不会比假装对他们做数学运算快吗?对于编译器来说,使用'f4 = f1 + f2 + f3;'对于中间值使用80位扩展格式而不是32位格式是很好的恕我直言,*假如它在处理这些事情时是一致的,但如果比较和演员没有完成适当的类型,他们是无意义的,“速度”是无关紧要的。 – supercat 2013-09-23 22:11:16

2

这篇文章解释了这是怎么回事:

http://www.exploringbinary.com/when-floats-dont-behave-like-floats/

基本上额外的精度可能会被保存在机器的不同表达的评价上,使这将是平等的花车不相等。

+0

非常感谢。我不知道;) – salteador 2012-03-26 23:12:50

+0

该标准要求演员丢弃任何额外的精度。海湾合作委员会在这方面只是被打破,这是一个已知的问题。这个问题可以通过'-ffloat-store'选项来部分支持,但是这只能解决分配问题,而不能解决问题。 – 2012-03-27 03:05:23