4

I know it's not "possible" to compare two real, but is it true for real which have denominator power of 2

Is equality of this king always return true

if( 3/4. == 6/8. ) {}
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Guillaume Paris
  • 10,303
  • 14
  • 70
  • 145
  • @Saphrosit: because I would like to have confirmation and advise/comment – Guillaume Paris Jun 05 '11 at 21:55
  • 9
    @Saphrosit: Floating point error is sufficiently complex that relying on testing random values is a great way to reach faulty conclusions. – Dennis Zickefoose Jun 05 '11 at 21:57
  • What exactly are you trying to do? There are many good answers below, so indeed if you have IEE754 floats, then small sums of powers of two are represented exactly (essentially any number that you can write exactly as a short binary expansion works). But do you actually need to compare numbers? If numeric comparison is important, you could check out comparison by "units in last place" (ULP), which is a great way to compare IEE754 floats. – Kerrek SB Jun 05 '11 at 23:07
  • can i use boost::math::float_distance(a, b) or nextafter to check if two double or just adjacent and then equal ? – Guillaume Paris Jun 06 '11 at 05:55
  • It looks like `boost::math::float_distance` does indeed implement ULP counting, so you can use that to see if two floats are "almost equal" (if they differ in fewer than, say, 3 ULP or something like that), but now I'm confused as to what you want. I don't understand your last comment language-wise, and I don't see how this relates to special floats which represent powers of 2. – Kerrek SB Jun 07 '11 at 18:25

4 Answers4

4

This kind of expression should always evaluate to true, with a few caveats:

  • The numerators don't exceed 2^52; otherwise they'll lose precision.
  • The denominators don't exceed the range provided by double-precision.
  • You must be working on a platform that uses radix-2 floating-point (which is basically all modern machines).
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • Why denominators can't get too large, could you complete please – Guillaume Paris Jun 05 '11 at 21:56
  • @Guillaume07: Well, in this case, so large (or in fact, so small) that they exceed the range of double-precision. Probably not going to be a concern for you! The other thing to consider is whether the numerators will exceed 2^52 (otherwise they'll lose precision). – Oliver Charlesworth Jun 05 '11 at 22:02
  • 2^53, actually, since the leading 1 is not explicitly stored. – Nemo Jun 06 '11 at 00:03
  • 2
    Also, you should probably `assert` (or `static_assert`) that `std:numeric_limits::radix == 2` before relying on this. – Nemo Jun 06 '11 at 00:05
3

I can't quote anything that says it's guaranteed, but logically it should work because all IEE754 floating point numbers are represented as M * 2 ^ E, where M and E are both integers (and may be negative).

Hence 3 / 4.0 and 6 / 8.0 are both exactly equal to 3 * 2 ^ -2 and fully representable in IEE754 format.

Furthermore, given:

% cat test.cc
double three_quarters = 3 / 4.0;
double six_eighths = 6 / 8.0;

We get:

% c++ -S test.cc
% cat test.s
.globl _three_quarters
        .data
        .align 3
_three_quarters:
        .long   0
        .long   1072168960
.globl _six_eighths
        .align 3
_six_eighths:
        .long   0
        .long   1072168960

Which shows that both expressions have been reduced (by the compiler) to the same constant value.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
1

There is no requirement that C++ implementations use IEEE 754 floating point (or similar). But if yours does, this should work fine.

Josh
  • 992
  • 5
  • 5
0

In general, whether floating-point equality comparison works depends not on the values, but how they were obtained.

e.g.

 double v = 4/3.0; // inexact
 double old_v = v;
 some_func_that_might_change_its_argument(&v);
 if (v == old_v) { ... }

is likely to work well despite the inexact value, while:

 double v = 0;
 for( int i = 0; i < 5; ++i ) v += 0.1;
 if (v == 0.5) { ... }

is likely to fail even though both sides of the inequality can be expressed as a simple rational number where the denominator is a power of 2.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720