【问题标题】:(float) casting does not work(浮动)铸造不起作用
【发布时间】:2012-03-26 22:25:01
【问题描述】:

我,尝试这个简单的代码。它显示了前 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;
}

di是double变量,但是我设置为(float)i,所以应该等于df,其实不然。

例如数字16777217用fdf表示为16777216,但di还是16777217,忽略 (float) 铸造。

这怎么可能?

**我正在使用这个:gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3

【问题讨论】:

  • 什么平台和编译器版本?
  • 你为什么要这样使用逗号运算符?绝对没有必要并增加了这样不必要的复杂性问题。
  • 你不需要说%lf。只要%f 就可以了,这意味着double

标签: c floating-point floating-point-conversion


【解决方案1】:

这篇文章解释了发生了什么:

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

基本上额外的精度可能会存储在机器上以用于不同的表达式评估,从而使相等的浮点数不相等。

【讨论】:

  • 非常感谢。我不知道;)
  • 标准要求强制转换丢弃任何额外的精度。 GCC 在这方面完全被破坏了,这是一个已知问题。使用-ffloat-store 选项可以部分回避这个问题,但这只能修复分配,而不是强制转换。
【解决方案2】:

与您的问题相关的是the C99 standard 中的 6.3.1.8:2:

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

特别是脚注 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 段是标准中我最讨厌的一段,我还在努力理解严格的别名。

【讨论】:

  • 非常感谢。我认为您是对的,编译器中存在错误(或功能?),因为 i!=f 是在双精度数而不是浮点数之间进行比较。
  • 这是 gcc 中一个由来已久的已知错误,开发人员几乎没有修复的意愿,因为它会适度损害不关心正确性的人的性能。如果您不关心使您的程序与旧 CPU 不兼容,您可以使用 -msse 解决问题(使用 SSE 而不是 FPU 进行浮点运算)。请注意,在 x86(可能还有 m68k?)以外的平台上不存在此问题。
  • @R..:如果他们想在不考虑正确性的情况下最大化性能,为什么不简单地让所有浮点计算返回 42.0?那不是比假装对他们做数学更快吗?恕我直言,编译器使用 80 位扩展格式而不是 32 位格式的中间值执行诸如 f4 = f1+f2+f3; 之类的事情是很好的,只要它在处理此类事情方面是一致的,但如果没有在正确的类型上进行比较和强制转换,它们毫无意义,“速度”无关紧要。
  • 它实际上已在 gcc 4.5.x 中修复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多