Why does this floating point comparison fail?

Don nospam at nospam.com
Thu Dec 16 00:56:02 PST 2010


Jonathan M Davis wrote:
> Maybe I'm just totally missing something, but this seems really wrong to me. 
> This program:
> 
> import std.stdio;
> 
> void main()
> {
>     writeln(2.1);
>     writeln(2.1 == 2.1);
>     writeln(3 * .7);
>     writeln(2.1 == 3 * .7);
> 
>     auto a = 2.1;
>     auto b = 3 * .7;
>     writeln(a);
>     writeln(b);
>     writeln(a == b);
> }
> 
> 
> 
> prints out
> 
> 2.1
> true
> 2.1
> false
> 2.1
> 2.1
> true
> 
> 
> How on earth is 2.1 not equal to 3 * .7?

0.7 is not exactly representable in binary floating point, nor is 2.1.
(they are the binary equivalent of a recurring decimal like 
0.333333333333...)

  Adding extra parens doesn't help, so
> it's not an operator precedence issue or anything like that. For some reason, 
> the result of 3 * .7 is not considered to be equal to the literal 2.1. What's 
> the deal? As I understand it, floating point operations at compile time do not 
> necessarily match those done at runtime, but 2.1 should be plenty exact for both 
> compile time and runtime. It's not like there are a lot of digits in the number, 
> and it prints out 2.1 whether you're dealing with a variable or a literal. 
> What's the deal here? Is this a bug? Or am I just totally misunderstanding 
> something?

Constant folding is done at real precision. So 3 * .7 is an 80-bit number.
But, 'a' has type double. So it's been truncated to 64 bit precision.

When something confusing like this happens, I recommend using the "%a" 
format, since it never lies.
writefln("%a %a", a, 3*.7);


More information about the Digitalmars-d-learn mailing list