5

I used to replace const with #define, but in the below example it prints false.

#include <iostream>
#define x 3e+38

using namespace std;

int main() {
    float p = x;
    if (p==x)
        cout<<"true"<<endl;
    else
        cout<<"false"<<endl;
return 0;
}

But if I replace

#define x 3e+38

with

const float x = 3e+38;

it works perfectly, question is why? (I know there are several topics discussed for #define vs const, but really didn't get this, kindly enlighten me)

Dr.PB
  • 959
  • 1
  • 13
  • 34
  • 4
    Try `#define x 3e+38f` – πάντα ῥεῖ Jan 17 '16 at 10:39
  • Waow, but why that does not work, as well as why and how this works? – Dr.PB Jan 17 '16 at 10:41
  • Don't use `==` to compare float/double – adrianm Jan 17 '16 at 10:43
  • If you omit the last `f`, then x is treated as a `double` while `p` is a `float`. – ViNi89 Jan 17 '16 at 10:44
  • Unless you're on a small embedded platform where every byte count, then there's really no need to use `float`, just use `double` everywhere and you no longer have to worry about problems like this. – Some programmer dude Jan 17 '16 at 10:45
  • then what to use to compare float/double? @adrianm – Dr.PB Jan 17 '16 at 10:46
  • 3
    @Mr.EU You might want to read ["Is floating point math broken?"](http://stackoverflow.com/questions/588004/is-floating-point-math-broken). It's very few floating-point values that can be checked for exact equality, most often you need to use an *epsilon*. You don't need to spend very long time with a search engine to find out about this. – Some programmer dude Jan 17 '16 at 10:48
  • @JoachimPileborg: True, but that is not the problem here. There's no math at all here. It's the roundtrip `double->float->double` which breaks things. Using either a `double` variable or a `float` literal would have solved it. – MSalters Jan 17 '16 at 10:55
  • 1
    You have learned a lesson that the compile has the concept of types - macros do not. Opt for the former rather than the latter and get the compile to pick up your errors - not your customers – Ed Heal Jan 17 '16 at 10:58

2 Answers2

5

In c++ the literals are double precision. In the first examples the number 3e+38 is first converted to float in the variable initialization and then back to double precision in the comparison. The conversions are not necessary exact, so the numbers may differ. In the second example numbers stay float all the time. To fix it you can change p to double, write

#define x 3e+38f

(which defines a float literal), or change the comparison to

if (p == static_cast<float>(x))

which performs the same conversion as the variable initialization, and does then the comparison in single precision.

Also as commented the comparison of floating point numbers with == is not usually a good idea, as rounding errors yield unexpected results, e.g., x*y might be different from y*x.

Ari Hietanen
  • 1,749
  • 13
  • 15
  • In short comparing `A` and `B` you can do something like `if (fabs(A-B)< EPSILON)`, where the `EPSILON` is small number (e.g., `0.0000001`) depending on the case. Sometimes you are better of comparing relative errors. See also http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison – Ari Hietanen Jan 17 '16 at 11:09
  • in normal case, what is the precision for `(a_float==b_float)`? – Dr.PB Jan 17 '16 at 11:37
  • 1
    That expression evaluates true only if they are exactly the same numbers. However, what is the smallest float larger than, e.g., a_float, depends on the absolute value of a_float. E.g,. `3e38f== 3e+38f+1.0f` evaluates to `true`, because float cannot hold 38 significant numbers. In this case the EPSILON should be at least about 1e28, because ` cout << 3e38f-3e38 << endl;` is `5.49776e+29` – Ari Hietanen Jan 17 '16 at 12:49
1

The number 3e+38 is double due its magnitude.

The assignment

float p = x; 

causes the 3e+38 to lose its precision and hence its value when stored in p.

thats why the comparison :

if(p==x)

results in false because p has different value than 3e+38.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
vsb
  • 11
  • 2