C 基础知识:double 变量不等于 double 表达式?

C fundamentals: double variable not equal to double expression?

我正在使用一个名为 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 具有误导性。同样,当我尝试下面的代码片段时

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

该条件将计算为真。

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

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

分配给类型为 floatdouble 的对象是一种强制舍入并消除多余精度的方法,但您也可以只向 [=20= 添加无偿强制转换] 如果您希望将其保留为没有赋值的表达式。

请注意,强制舍入到所需精度并不等同于以所需精度执行算术;而不是一个舍入步骤(在算术过程中)你现在有两个(在算术过程中,再次降低不需要的精度),并且在第一次舍入给你一个精确的中点的情况下,第二次舍入可以进入 'wrong'方向。这个问题通常被称为双舍入,它使某些类型的计算的超精度明显低于标称精度。