-5

Please before you think that I'm asking the same N% Question read it first and please pay Attention to it.

I'm working on a project where I have more functions which returns double and it may be possible that some of them are the same which is a good thing in my project and if is true then I need a double comparison to see if are equal.

I know that doing an equality comparison if( x == y ) is not a smart thing and we don't need to speak why, but we can check for < or > which is the part of this Question.

Does the language (standard) guarantee this, that the comparison < and > are 100%?

If yes then, the following program can be used:

#include <stdio.h>

int main(void){
    double x = 3.14;
    double y = 3.14;

    if( x < y || x > y){
        /* Are not Equal */
    }else{
        /* Are Equal, foo() will be called here\n" */
        foo(x, y);
    }
}

Does foo(x, y); get executed? BecauseX and Y should be equal here.

EDIT: This question doesn't seek a way to compare two double, it is only the fact that should I use, or should I don't use < > instead of ==

Michi
  • 5,175
  • 7
  • 33
  • 58
  • Really Down voter? You better be kidding me. – Michi Jun 07 '16 at 17:55
  • I think this is slick. Voted up. – nicomp Jun 07 '16 at 17:55
  • @nicomp No problem :) – Michi Jun 07 '16 at 17:56
  • 1
    Michi, you already know the standard, so what did you find in it that does state comparison of floats is not monothonic? Or how do you conclude it would not be? Note that also comparison for equality is exact. It is just that rounding errors and inexact representation of fractional values can result in problems, not the operator itself. – too honest for this site Jun 07 '16 at 17:57
  • 4
    The DV is well justified, as the question lacks any research. Also it is an XY-problem. You have to compare with some tolerance for equality. – too honest for this site Jun 07 '16 at 17:57
  • @squeamishossifrage I meant `x y` – Michi Jun 07 '16 at 17:58
  • The question IS the research. It's cool. – nicomp Jun 07 '16 at 17:58
  • What is the question here? What happens when you run the given program? – thelaws Jun 07 '16 at 17:59
  • @Olaf I see your point and you right, I was thinking on something else. – Michi Jun 07 '16 at 17:59
  • 1
    More relevant is how you compute the values to be compared. Otherwise your question is "are computations repeatable?" – Weather Vane Jun 07 '16 at 18:00
  • @nicomp: It is neither hot nor cool. Please read site-rules. and DV reasons. showing no research is a valid reason. – too honest for this site Jun 07 '16 at 18:00
  • @thelaws The Question is clear enough, Which part you don't understand? – Michi Jun 07 '16 at 18:00
  • @olaf - the research IS the question. – nicomp Jun 07 '16 at 18:01
  • @WeatherVane I have two functions which returns same results like `3,14` and I wasn't sure about comparison. – Michi Jun 07 '16 at 18:01
  • 1
    you believe `x == y` is a bad idea but `(x < y || x > y)` is not? – GabrielF Jun 07 '16 at 18:02
  • @Michi why would the two identical assignments in the question not be "equal"? – Weather Vane Jun 07 '16 at 18:02
  • @WeatherVane this isn't OP's real code. – GabrielF Jun 07 '16 at 18:03
  • 1
    Oh not again. "This is only *something like my code*". – Weather Vane Jun 07 '16 at 18:03
  • 1
    @Michi ever seen this: https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html ? – GabrielF Jun 07 '16 at 18:04
  • I think you should always treat an FP number as an `exact + epsilon`, where `epsilon` is a *small random* signed real number. Then you will have your question ruled out. – Eugene Sh. Jun 07 '16 at 18:07
  • `double a = b = 3.14` always results in `a == b` being true. Any other way of computing `a` and `b` can result in `a` being "very close" to `b` but not equal. –  Jun 07 '16 at 18:11
  • What can I say a Question like [THIS](http://stackoverflow.com/questions/1839422/strange-output-in-comparison-of-float-with-float-literal) shows more research. Thank you guys. – Michi Jun 07 '16 at 18:24
  • @Michi you realize the linked question was posted in 2009, right? And it's just much more humble question... your lack of research combined with your first sentence didn't help you much. – GabrielF Jun 07 '16 at 18:49
  • @GabrielF You are a funny guy. Does that make a difference? What ever I got partially an Answer and I'm fine with it. – Michi Jun 07 '16 at 18:53
  • 1
    @Eugene Sh. Disagree with "treat an FP number as an exact + epsilon, where epsilon is a small random signed real number". Such an approach treats all small numbers smaller than `epsilon*(1 + 1/epsilon)` as equal even though that may be 40% of all FP numbers. And for large numbers , `> 1/epsilon`, it provides no improvement over `epsilon == 0`. FP error assessment is for more complex than working with a fixed `epsilon`. – chux - Reinstate Monica Jun 07 '16 at 21:51

5 Answers5

3

I know that doing an equality comparison if( x == y ) is not a smart thing

This is simply not true. It may be the right thing to do or the wrong thing to do, depending on the particular problem.

if (x < y || x > y)

This has guaranteed exactly the same effect1 as

if (x != y)

and the opposite effect of

if (x == y)

When one is wrong, the other is wrong too. When one is right, the other is right as well. Writing an equality condition with < and > symbols instead of == or != doesn't suddenly make it smarter.


[1] Except maybe when one of the operands is a NaN.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
2

some of them are the same ... and if is true then I need a double comparison to see if are equal.

OP is questioning two different ways for testing FP equality and wondering if they are the functionally alike.

Aside from maybe NaN, which is not well defined by C, (but well defined by IEEE 754), both comparisons are alike yet fail conically equivalence testing.

Consider this double code:

if (a==b) {
  double ai = 1.0/a;
  double bi = 1.0/b;
  printf("%d\n", ai == bi);
} else {
  printf("%d\n", 1);
}

Is the result always "1"? Below is an exception (mouse over to see)

Consider a=0.0; b=-0.0. Both are equal to each other, but their inverses typically are not the same. One being positive infinity, the other: negative infinity.

The question comes down to how equal do you need? Are NaN important? Using memcmp(&a, &b, sizeof a) is certainly a strong test and maybe too strong for on select systems FP numbers can have the same non-zero value, yet different encodings. If these differences are important, or maybe just the exceptional case above, is for OP to decide.


For testing if 2 different codes/functions were producing the same binary64 result, consider rating their Unit-in-the-Last-Place difference. Something like the following: compare unsigned long long ULP_diff() against 0, 1 or 2. depending on your error tolerance.

// not highly portable
#include <assert.h>
unsigned long long ULP(double x) {
  union {
    double d;
    unsigned long long ull;
  } u;
  assert(sizeof(double) == sizeof(unsigned long long));
  u.d = x;
  if (u.ull & 0x8000000000000000) {
    u.ull ^= 0x8000000000000000;
    return 0x8000000000000000 - u.ull;
  }
  return u.ull + 0x8000000000000000;
}

unsigned long long ULP_diff(double x, double y) {
  unsigned long ullx = ULP(x);
  unsigned long ully = ULP(y);
  if (x > y) return ullx - ully;
  return ully - ullx;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

If you want fractional number equality, you either have to use an epsilon comparison (ie. check if the numbers are close enough to one another within a specific threshold), or use some fixed-point arithmetic very carefully to avoid rounding errors.

And yes, this same question has been asked more times than necessary:

You need to do more reading into how comparisons work, and specifically why floating point equality doesn't work. It's not an issue with the equals operator itself, as you appear to think (For arithmetic types [when no special values like NaN are involved], !(x > y || y > x) will always be the same as x == y. In fact, most compilers will optimize x < y || x > y to x != y), but rather because rounding error is a basic part of floating point operation in the first place. x == y does indeed work for floating point types, and you can do it freely. It becomes an issue after you do any arithmetic operation and then want to compare them, because it's unpredictable what the rounding error will do.

So essentially, yes. Compare equality all you want unless you are actually doing anything with the doubles. If you are just using them as an index or something of the like, there shouldn't be a problem, as long as you know you are assigning them the same value. Using boolean identities won't save you from the basic functionality of floating-point numbers.

Taywee
  • 1,313
  • 11
  • 17
  • I never asked for a way to do a comparison, what I asked was, if I can/should use **< >** instead of **==**, but it happens, that here we read and understand what we want and not what OP ask – Michi Jun 07 '16 at 18:59
  • I don't understand what you mean. Of course you can use < and > instead of ==, but if it does the same thing by definition then why would you? – Taywee Jun 07 '16 at 19:06
  • This Question is a big mistake. I can't delete it. I up voted your answer any way. – Michi Jun 07 '16 at 19:21
1

First of all your conditional is a little off. To check for non equality you want

( x < y || y < x)

not

(x < y || y > x ) 

which just checks the same thing twice, meaning x < y comes back as false.

Ignoring that small issue:

Yes > and < should be 100% in that it is almost always the same as the ==. The only difference is different behavior with Nan. But it doesn't fix your problem.

Here is a really contrived example.

#include <stdio.h>

void foo(double x, double y){
    printf( "OK  a:%f, b:%f\n",x,y);
}

void bar(double x, double y){
    printf( "BAD a:%f, b:%f\n",x,y);
}

int main(void){

    double x = 3.14;
    double y = 3.14;


    if( x < y || y < x){
        /* Are not Equal */
        bar(x, y);
    }else{
        /* Are Equal, foo() will be called here\n" */
        foo(x, y);
    }

    for( int i = 0; i < 1000; i++) {
        y = y + 0.1;
    }

    x = x + 100;

    if( x < y || y < x){
        bar(x, y);
    }else{
        /* Are Equal, foo() will be called here\n" */
        foo(x, y);
    }
}

Here is you output (hint its BAD)

$ ./a.exe
OK  a:3.140000, b:3.140000
BAD a:103.140000, b:103.140000

Best practice I know for double equality is to check there closeness within some epsilon,

eps = 0.00000000001

if( abs( x - y ) < eps ) {
    printf("EQUAL!");
}
gbtimmon
  • 4,238
  • 1
  • 21
  • 36
-2
#include <stdio.h>

int main(void){
double x = 3.14;
double y = 3.14;

if( x < y || x > y){
    /* Are not Equal */
}else{
    /* Are Equal, foo() will be called here\n" */
    printf("yes");
   }
}

prints yes

pst ypks
  • 63
  • 1
  • 5