2

I am aware of the floating point errors as I had gained some knowledge with my question asked here in SE Floating Point Errors.

What I am finding it difficult to understand is, the output of the following program.

        double d1 = 0 + 1.123 + 2.456;
        double d2 = 3.579;

        float f1 = 0f + 1.123f + 2.456f;
        float f2 = 3.579f;

        long l1 = (long)(0 + 1.123 + 2.456);
        long l2 = (long)3.579;

        System.out.println(d1==d2);  // Output = false;
        System.out.println(f1==f2);  // Output = true;
        System.out.println(l1==l2);  // Output = true;

Why is the output "false" for double and not for float, even when float is single precision 32 bit and double is double precision 64 bit. Oracle docs

Any help with this would be highly appreciated.

JNL
  • 904
  • 2
  • 8
  • 18
  • 2
    Print out the values. Consider that the rounding errors and actual representation are different for the two types. Suggested reading: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – Oded Jul 18 '13 at 21:12
  • 1
    From Stack Overflow: [What's the reason for this if statement not working (double precision/object uniqueness)](http://stackoverflow.com/questions/9124019/whats-the-reason-for-this-if-statement-not-working-double-precision-object-uni) –  Jul 18 '13 at 21:18
  • 2
    or convert both to their binary representation with [Double.doubleToLongBits(long)](http://docs.oracle.com/javase/6/docs/api/java/lang/Double.html#doubleToLongBits%28double%29) and the float variant – ratchet freak Jul 18 '13 at 21:18
  • 3
    never EVER use strict equality in floating point comparisons. – Deer Hunter Jul 18 '13 at 21:33

1 Answers1

9

Consider this hypothetical.

You have two data types. One is a floating point number with 32 bits of precision that is base 3 (represented by the digits 0, 1, and 2). The other is a floating point number with 64 bits of precision that is base 4.

Given this code:

float a = .3 + .6
float b = .9;

print(a == b)

The comparison will return true if base 3 floats are used, and false if base 4 floats are used, even though the base 4 float has a much higher precision.

Why is this? Because the numbers 3, 6, and 9 can be represented exactly in the base 3 float, but can only be approximated in the base 4 float, no matter how many digits of precision there are.

This is why floating point numbers should never be compared using ==. They should always be compared using a range of allowable error.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
  • So this would be basically because the decimals are not represented correctly in binary form and when we compare, we basically compare bits? – JNL Jul 18 '13 at 21:31
  • Yes. They're not represented *exactly* in binary form; they are (almost) always approximations. Further, the internal representation of the 32 bit float is different than that of the 64 bit float. – Robert Harvey Jul 18 '13 at 21:33
  • Beautiful. This definitely comes through experience. Thanks Robert – JNL Jul 18 '13 at 21:42
  • I am not a C# developer, but it seems there's a datatype "decimal" in C#, so that would basically go through the same error? or have they implemented it in a better way to handle such cases? – JNL Jul 18 '13 at 22:37
  • 1
    @JNL: See http://stackoverflow.com/q/5940222 – Robert Harvey Jul 18 '13 at 22:42
  • Neither 3/10, 6/10, or 9/10 are exactly expressible in base 3 or base 4, because 10=2*5, and 5 is relatively prime to both 3 and 4. – kevin cline Jul 18 '13 at 23:00
  • @kevincline: I see the problem, but I'm leaving the answer as it is. The base, as used here, is meant to convey the *internal representation* of the numbers, not their external representation, and the example is meant to be merely illustrative, not mathematically rigorous. – Robert Harvey Jul 18 '13 at 23:36
  • Out of curiosity, so what are the other ways that are used when we deal with financial or banking data where we need to handle data in "double"? One way is to have a tolerance, is there any other way too? This is just out of curiosity. – JNL Jul 19 '13 at 15:17
  • @JNL: The correct answer is, *you don't.* Financial data is always handled in a `decimal`, `integer` or fixed point type. – Robert Harvey Jul 19 '13 at 17:28
  • @kevincline Relative primeness (to the base) is not the right distinction here (e.g. 1 is relatively prime to everything and can be represented precisely). The fraction _p_ / _q_ (in lowest terms, i.e. with *p*, *q* relatively prime) can be represented as a terminating “decimal” in base *b* iff *q* divides some power of *b*, i.e. iff *all* prime factors of *q* are also prime factors of *b*. (For them not to be relatively prime it suffices that *one* prime factor of *q* is also a prime factor of *b*, but we really need *all*.) – Eike Schulte Oct 14 '22 at 06:42