json-tutorial icon indicating copy to clipboard operation
json-tutorial copied to clipboard

Failed to correctly compare two doubles simply with `==` in `EXPECT_EQ_DOUBLE`.

Open izackwu opened this issue 6 years ago • 6 comments

In test.c, we compare the equality of two doubles simply with ==:

#define EXPECT_EQ_DOUBLE(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%.17g")

I don't know whether it works fine for others, but it just won't work on my computer. (Windows 10, 64, with (MinGW.org GCC-8.2.0-3) 8.2.0)

To figure out what's wrong, I did a simple test with a seperate C file:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
    if(3.1416 != strtod("3.1416", NULL)){
        printf("NOT EQUAL!\n");
    }else{
        printf("EQUAL.\n");
    }
    return 0;
}

The interesting thing happens: the output of this program depends on the C standard I use to compile it.

If I compile it with gcc -std=c89 gcc -std=c99 gcc -std=c11 or gcc -std=c17, the output of running the executable will be NOT EQUAL!.

If I compile it with gcc(no standard specified and therefore using -std=gnu11), the output is EQUAL.

I don't know why this happens, but I think we'd better write EXPECT_EQ_DOUBLE in a more universal way despite the difference between OS and gcc version.

izackwu avatar Aug 23 '19 13:08 izackwu

I found a feasible workaround:

#define EXPECT_EQ_DOUBLE(expect, actual) EXPECT_EQ_BASE((double)(expect) == (actual), expect, actual, "%.17g")

By explictly converting expect to double, this issue gets solved.

But I still have no idea about why this issue happens and why I can fix it in such a way.

izackwu avatar Aug 23 '19 13:08 izackwu

Because of floating point error, the compare of equality of floating point numbers is unreliable.

Syopain avatar Aug 28 '19 08:08 Syopain

Because of floating point error, the compare of equality of floating point numbers is unreliable.

@Syopain True, but see these issues: #29 #69

izackwu avatar Aug 28 '19 10:08 izackwu

@keithnull strtod的实现应该是逐位计算的,所以计算过程中可能会有误差,我觉得这里应该用fabs(expect - actual) < (EPS) 来比较

Syopain avatar Aug 28 '19 12:08 Syopain

@keithnull strtod的实现应该是逐位计算的,所以计算过程中可能会有误差,我觉得这里应该用fabs(expect - actual) < (EPS) 来比较

@Syopain You are right. But how to explain that (double)3.14156 == strtod("3.14156") works while 3.14156 == strtod("3.14156") not? I don't think this is due to the rounding error or strtod.

izackwu avatar Aug 28 '19 13:08 izackwu

@keithnull strtod的实现应该是逐位计算的,所以计算过程中可能会有误差,我觉得这里应该用fabs(expect - actual) < (EPS) 来比较

@Syopain You are right. But how to explain that (double)3.14156 == strtod("3.14156") works while 3.14156 == strtod("3.14156") not? I don't think this is due to the rounding error or strtod.

I think it may depend on the environment.

Syopain avatar Aug 28 '19 15:08 Syopain