【问题标题】:C fundamentals: double variable not equal to double expression?C基础知识:双变量不等于双表达式?
【发布时间】:2016-10-04 05:55:12
【问题描述】:

我正在使用一个名为 indata 的双精度数组(在堆中,使用 malloc 分配)和一个名为 sum 的本地双精度。

我写了两个不同的函数来比较indata中的值,得到了不同的结果。最终,我确定差异是由于一个函数在条件测试中使用了表达式,而另一个函数在同一条件测试中使用了局部变量。我希望这些是等价的。

我的函数 A 使用:

    if (indata[i]+indata[j] > max) hi++;

我的函数 B 使用:

    sum = indata[i]+indata[j];
    if (sum>max) hi++;

在通过相同的数据集和max 之后,我最终得到不同的hi 值,具体取决于我使用的函数。我相信功能 B 是正确的,而功能 A 具有误导性。同样,当我尝试下面的 sn-p 时

    sum = indata[i]+indata[j];
    if ((indata[i]+indata[j]) != sum) etc.

该条件将评估为真。

虽然我知道浮点数不一定能提供精确的表示,但为什么当作为表达式评估而不是存储在变量中时,这种不精确的表示会发生变化?推荐的最佳做法是在条件之前始终评估这样的双重表达式吗?谢谢!

【问题讨论】:

  • 这基本上是因为计算机不能完全精确地表示数字。了解浮点数。
  • @iharob 他在最后一段中承认了这一点。但它并没有解释为什么它会根据您是否将结果分配给变量而有所不同。
  • 在 B 中进行赋值时,需要将值四舍五入到最接近的 double 值(通常为 64 位)。在函数 A 中,条件表达式可以使用更高的精度(例如 80 位)进行计算。
  • @user3386109:如果代码确实是针对 x86 而不是 x86-64 编译的,因此它使用 x87 而不是 SSE 浮点指令,那么这确实是最可能的解释。

标签: c syntax floating-point expression floating-accuracy


【解决方案1】:

我怀疑您使用的是 32 位 x86,这是唯一受超精度影响的通用架构。在 C 中,floatdouble 类型的表达式实际上被评估为 float_tdouble_t,它们与 floatdouble 的关系反映在 FLT_EVAL_METHOD 宏中。在 x86 的情况下,两者都定义为long double,因为 fpu 实际上无法执行单精度或双精度的算术运算。 (它具有允许这样做的模式位,但行为稍有错误,因此无法使用。)

分配给floatdouble 类型的对象是强制舍入并消除多余精度的一种方法,但如果您愿意将其保留为一个没有赋值的表达式。

请注意,强制舍入到所需精度并不等同于以所需精度执行算术;而不是一个舍入步骤(在算术期间),您现在有两个(在算术期间,并再次降低不需要的精度),并且在第一个舍入为您提供精确中点的情况下,第二个舍入可能会出现“错误” ' 方向。这个问题通常被称为双舍入,对于某些类型的计算,它使超额精度明显低于标称精度。

【讨论】:

  • 感谢您的解释。我在运行 64 位 Windows 7 的 i7-3770 cpu 上运行代码。但是,我的编译器是 minGW,它是一个 32 位应用程序。我将调查编译器设置。我知道有一个硬件级别的精度高于两倍,并且在使用表达式与变量时会更加小心。仅供参考,在这种情况下,类型转换表达式实际上不起作用 - 与没有它的行为相同。
  • -std=c99-fexcess-precision=standard 试试演员阵容。在某些不符合标准的模式下,GCC 的行为会出错。
  • 谢谢 - 这些编译器命令行选项中的任何一个都可以解决问题,以便此代码正常运行:if ((double)(indata[i]+indata[j]) > max) hi++;
猜你喜欢
  • 2011-04-13
  • 1970-01-01
  • 1970-01-01
  • 2019-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多