*完全*相等的双精度返回0表示(a == b)

时间:2012-04-04 06:52:39

标签: c comparison floating-point

  

可能重复:
  C compiler bug (floating point arithmetic)?

我有两个双打,我可以保证完全等于150个小数位 - 即。以下代码:

printf("***current line time is %5.150lf\n", current_line->time);
printf("***time for comparison is %5.150lf\n", (last_stage_four_print_time + FIVE_MINUTES_IN_DAYS));

...返回:

***current line time is 39346.526736111096397507935762405395507812500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
***time for comparison is 39346.526736111096397507935762405395507812500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

FIVE_MINUTES_IN_DAYS是#defined,current_line->timelast_stage_four_print_time都是双打。

我的问题是我的调试代码的下一行:

printf("if condition is %d\n", (current_line->time >= (last_stage_four_print_time + FIVE_MINUTES_IN_DAYS)));

返回以下内容:

if condition is 0

谁能告诉我这里发生了什么?我知道floatsdoubles的非十进制/不精确性质,但这些都不会出现任何错误(原始数据都是用sscanf或#defined读取的并且都指定为10位小数)。

编辑:我的错误是假设printf - 双精确地在内存中准确地表示了它们,这是错误的,因为正在计算一个值。将(last_stage_four_print_time + FIVE_MINUTES_IN_DAYS)声明为threshold_time并使用它来修复问题。我将确保使用epsilon进行比较 - 我知道这是要走的路,我只是为什么这些我(错误地)认为看起来相同的值明显不相等而感到困惑。

6 个答案:

答案 0 :(得分:4)

Floats当然不准确到150位有效数字,所以我不确定从“视觉”比较中得出什么结论(如果有的话)。

另一方面,这些值显然不是相同的(并且它们怎么可能,因为其中一个是在现场计算加上?)。因此,您所看到的行为是出乎意料的并不是很清楚。

不要永远比较这样的浮点数,只需做差异与epsilon的标准比较。

答案 1 :(得分:4)

了解浮点表示(特别是http://en.wikipedia.org/wiki/IEEE_754-2008)。尝试将包含双精度的字节的实际内容打印为十六进制,并且它们不会逐位匹配。 浮子的正确比较是在Knuth(Seminumerical算法)中。简单(用int替换bool,用double替换float,用1替换true):

bool almostEqual(float x, float y, float epsilon)
{
    if (x == 0.0 && y == 0.0) {
        return true;
    }

    if (fabs(x) > fabs(y)) {
        return fabs((x - y) / x) < epsilon;
    } else {
        return fabs((x - y) / y) < epsilon;
    }
}

答案 2 :(得分:3)

您应始终使用EPSILON值来比较浮点数和双精度数以检查是否相等。即使看起来相同,内部表示也不能保证匹配,因为这些类型的数字以二进制形式表示。

您可以执行类似

的操作
#define EPSILON 0.00001
...
if (fabs(a - b) <= EPSILON) return 1; // they are equal
return 0;

答案 3 :(得分:2)

耶稣对如何解决这个问题是对的。

至于为什么......在一种情况下,你读取一个常数值,在另一种情况下你执行一个加法运算。即使打印输出完全相同,二进制表示也可能略有不同。

尝试检查支持两个双精度的内存,看看是否有任何不同(会有差异)。

对于综合治疗,我建议

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

答案 4 :(得分:1)

通常,您不应使用==来比较浮点数或双精度数。您应该检查差异是否小于某个小数字。

double second_number = last_stage_four_print_time + FIVE_MINUTES_IN_DAYS;
if (fabs(current_line->time - second_number) < 0.001 || current_line->time > second_number){
  // your comparison code
}

答案 5 :(得分:1)

首先,双打只有15-16位小数(log_2为52位matissa)。

其次,如果你想比较,请使用已经提到过的epsilon。

第三,要进行调试,请打印十六进制值。