LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   C compare double (https://www.linuxquestions.org/questions/programming-9/c-compare-double-612682/)

h/w 01-10-2008 03:31 PM

C compare double
 
Here's something new to me in GCC; a double comparison isn't straight-forward, or at least it doesn't seem to me from my test:

Code:

int simple(double fv, double pv, double r, double t) {
  printf("in simp\n");
  printf("fv = %lf\n", fv);
  printf("pv = %lf\n", pv);
  printf("r = %lf\n", r);
  printf("t = %lf\n", t);

  if(0.0 == fv) {
    printf("Finding FV\n");
  } else if(0.0 == pv) {
    printf("Finding PV\n");
  } else if(0.0 == r) {
    printf("Finding R\n");
  } else if(0.0 == t) {
    printf("Finding T\n");
  } else {
    return -1;
  }

  return 0;
} //simple

The output is:
Code:

in simp
fv = 200.000000
pv = 0.000000
r = 4.500000
t = 2.000000

None of the if's are taken.

Can someone explain why, or what I'm doing wrong here?
Thanks.

bigearsbilly 01-10-2008 03:55 PM

hmmm, it works on solaris 10
(I use the Sun compiler)


Code:

#include <stdio.h>


int simple(double fv, double pv, double r, double t) {
  printf("in simp\n");
  printf("fv = %lf\n", fv);
  printf("pv = %lf\n", pv);
  printf("r = %lf\n", r);
  printf("t = %lf\n", t);

  if(0.0 == fv) {
    printf("Finding FV\n");
  } else if(0.0 == pv) {
    printf("Finding PV\n");
  } else if(0.0 == r) {
    printf("Finding R\n");
  } else if(0.0 == t) {
    printf("Finding T\n");
  } else {
    return -1;
  }

  return 0;
} //simple

int main(void)
{
    simple(200,0.000000,4.5,2);
}

Code:

$
$ ./1
in simp
fv = 200.000000
pv = 0.000000
r = 4.500000
t = 2.000000
Finding PV
$


h/w 01-10-2008 03:59 PM

I should have mentioned I was trying this on a cygwin env. Never saw this before when I worked on any of the *nix env's myself.
Strange, but there must be a reason ...

bigearsbilly 01-10-2008 04:01 PM

unfort I can't test it as I don't have any DOS op systems.
;)

I could fire up my laptop and start xp on my vmware I suppose.

paulsm4 01-10-2008 04:31 PM

h/w, bigearsbilly -

For grins, I cut/pasted the original subroutine and bigearsbilly's "main()" ... and got exactly the same results as bigearsbilly.

Everything looks OK.

On both DJGPP (GCC 4.2, DOS) and SuSE (GCC 3.3.5, Linux):
Quote:

in simp
fv = 200.000000
pv = 0.000000
r = 4.500000
t = 2.000000
Finding PV
'Sounds like a problem with your version of Cygwin C/C++?

makyo 01-10-2008 06:51 PM

Hi.

A display of "0.000000" does not mean the item is zero. It means that to 7 places the value is zero.

Although this may not be the cause of the situation here, floating point comparisons should almost never be for equality because of round-off that occurs in calculation with the approximations we use.

Perhaps printing the values in hex or octal would be useful.

Also we don't know (I don't know) what instructions are generated for the comparison in the if ... cheers, makyo

paulsm4 01-10-2008 07:44 PM

Hi, Makyo -

Although in general your argument is correct...
... but an IEEE 754 "0.0" is binary identical to "0.000000000000000":
http://en.wikipedia.org/wiki/IEEE_754

Quote:

Quote:

Although this may not be the cause of the situation here, floating point comparisons should almost never be for equality because of round-off that occurs in calculation with the approximations
<= I agree completely
Quote:

Quote:

Perhaps printing the values in hex or octal would be useful.
<= An excellent suggestion. I'm curious myself!
H/W -
Could you please:
1. Tell us your Cygin/GCC version ("gcc -v" should tell you)
2. Tell us what kind of PC you're running on (who knows - maybe you're using some kind of FPU that doesn't use IEEE floating point!)
3. Dump the data values in hex (if convenient: gdb is one way)
4. Post back the results (we're curious!)

Thanx in advance .. PSM

makyo 01-10-2008 08:22 PM

Hi, paulsm4.
Quote:

Originally Posted by paulsm4 (Post 3018446)
Although in general your argument is correct...
... but an IEEE 754 "0.0" is binary identical to "0.000000000000000":
http://en.wikipedia.org/wiki/IEEE_754

That was not the thrust of my comment, I should have been more precise. I was writing about the result of the printf statement.

Most of the tests that people performed were with calls that specified constants. The OP did not share how the argument values were obtained when the call was made ... cheers, makyo

bigearsbilly 01-11-2008 06:14 AM

Quote:

Originally Posted by makyo (Post 3018400)
Hi.

Although this may not be the cause of the situation here, floating point comparisons should almost never be for equality because of round-off that occurs in calculation with the approximations we use.

exactly, observe:

Code:

#include <stdio.h>
#include <math.h>


int main(void)
{
        float  y;
        float  x;

        for(;;) {
            printf("\nEnter a number:");
            scanf("%f", &x);
            y = sqrtf(x);
            printf("x=%f, y=%.33f\n", x, y);
            y *= y;
            printf("x=%f, y=%.33f\n", x, y);
        }
}

Code:

Enter a number:99

x=99.000000, y=9.949873924255371093750000000000000
x=99.000000, y=98.999992370605468750000000000000000


h/w 01-11-2008 09:20 AM

Thanks for the replies, all.
I'm aware of not doing FP compares, but had assumed that zero would not have this same behaviour. I still am not convinced entirely as we don't see this on other systems, but hey ...

paulsm4: it's gcc 3.4.4 on a 64-bit Windows XP. Would using a %o format specifier do to get the octal? Wouldn't it be incorrect against "double's"?

Thanks again.

paulsm4 01-11-2008 11:12 AM

Hi -

I think we're all on the same page:

a) checking for equality with floating point numbers (which are, by definition, imprecise) is dangerous...
... but ..
b) you *should* be able to compare a double variable with the value "0.0" with a floating point literal "0.0" and reliably get "equals".

For whatever it's worth, I tried your program on a *third* different PC: a 64-bit AMD running Suse 10.x/Gnu 4.x... and it worked OK. No problems with "0.0".

I guess I'd be suspicious of your copy of Cygwin. If you wanted to pursue it further, the next step would be to compile with "gcc -S" and look at the assembler output of the comparision.

Your .. PSM

h/w 01-11-2008 12:19 PM

Hi Paul,
It's not worth the effort to look into what makes it different on cygwin. It was just a short program I was writing, and it just so happens it was on an env I don't use otherwise (cygwin.)
Anyway, the topic and all your replies just iterated some good points to remember.
Thanks all.

jim mcnamara 01-11-2008 12:38 PM

The C standard defines macros like isgreaterequal, isgreater, and so on for comparing fp datatypes. Therefore,
Code:

if ( ! islessgreater(a,b))
is one sure way to do a == boolean compare for floating point values. The advantage of the macros aside from portability, is that it will not raise exceptions on non-normal fp numbers.

See math.h for all of them.

h/w 01-11-2008 12:51 PM

Quote:

Originally Posted by jim mcnamara (Post 3019239)
The C standard defines macros like isgreaterequal, isgreater, and so on for comparing fp datatypes. Therefore,
Code:

if ( ! islessgreater(a,b))
is one sure way to do a == boolean compare for floating point values. The advantage of the macros aside from portability, is that it will not raise exceptions on non-normal fp numbers.

See math.h for all of them.

Interesting, jim. Wasn't aware of those macros.
Thanks.

paulsm4 01-11-2008 01:52 PM

Hi, Jim -

"islessgreater()" and friends are ISO C99 macros. Newer versions of GCC/Linux are pretty good about supporting them, but you're not going to find them elsewhere (for example, it's *not* in my copy of MSVC ... but I haven't seen the new "Orcas"/VS2008 yet ;-))

Even then, you probably have to add special flags to get it to compile/link, e.g.:
Quote:

gcc -std=c99 -o simple simple.c -lm
Again, the basic issue is that what H/W was trying *should* work. I would definitely characterize the problem as a compiler issue, *not* a programming error.

IMHO .. PSM


All times are GMT -5. The time now is 08:02 PM.