2
int main(void)
{
    float me = 1.1;       
    double you = 1.1;   

    if ( me == you ) {
        printf("I love U");
    } else {
        printf("I hate U");
    }
}

This prints "I hate U". Why?

Samer
  • 1,923
  • 3
  • 34
  • 54
  • `1.1` is by default `double`, converted to `float` when used to initialize `me`. Before `me` is compared with `you`, `me` is converted back to `double`. If the first conversion is lossy, you get a `FALSE` when compared equal. Down vote for notation of `me` `U` which makes the question uncomfortable to write an answer to. – user3528438 Jun 12 '15 at 17:09
  • Welcome to SO. Next time you provide proper formatting and a correct question. In other words a [MCVE](http://stackoverflow.com/help/mcve) – too honest for this site Jun 12 '15 at 17:26
  • 2
    the compiler hates you... – bolov Jun 12 '15 at 17:27
  • @user3528438: just let the kids use their own language. For an answer, you can use yours. If he cannot transpose, it is his problem actually. (However, he has a point: use more neutral terms). – too honest for this site Jun 12 '15 at 17:33
  • What sites have you searched on? Links? – Martin James Jun 12 '15 at 18:09
  • Did you even try to look for an existing answer to this question? http://stackoverflow.com/questions/17343155/double-and-float-comparison http://stackoverflow.com/questions/9014303/comparing-float-and-double http://stackoverflow.com/questions/6722293/why-comparing-double-and-float-leads-to-unexpected-result – Stephen Canon Jun 12 '15 at 23:41

4 Answers4

3

Floats use binary fraction. If you convert 1.1 to float, this will result in a binary representation. Each bit right if the binary point halves the weight of the digit, as much as for decimal, it divides by ten. Bits left of the point double (times ten for decimal).

in decimal: ... 0*2 + 1*1 + 0*0.5 + 0*0.25 + 0*0.125 + 1*0.0625 + ...
binary:          0    1  .  0       0        0         1          ...
2's exp:         1    0    -1      -2       -3        -4
(exponent to the power of 2)

Problem is that 1.1 cannot be converted exactly to binary representation. For double, there are, however, more significant digits than for float.

If you compare the values, first, the float is converted to double. But as the computer does not know about the original decimal value, it simply fills the trailing digits of the new double with all 0, while the double value is more precise. So both do compare not equal.

This is a common pitfall when using floats. For this and other reasons (e.g. rounding errors), you should not use exact comparison for equal/unequal), but a ranged compare using the smallest value different from 0:

#include "float.h"

...
// check for "almost equal"
if ( fabs(fval - dval) <= FLT_EPSILON )
    ...

Note the usage of FLT_EPSILON, which is the aforementioned value for single precision float values. Also note the <=, not <, as the latter will actually require exact match).

If you compare two doubles, you might use DBL_EPSILON, but be careful with that.

Depending on intermediate calculations, the tolerance has to be increased (you cannot reduce it further than epsilon), as rounding errors, etc. will sum up. Floats in general are not forgiving with wrong assumptions about precision, conversion and rounding.

Edit:

As suggested by @chux, this might not work as expected for larger values, as you have to scale EPSILON according to the exponents. This conforms to what I stated: float comparision is not that simple as integer comparison. Think about before comparing.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • With FP math, suggest `fabs()` rather than `abs()`. – chux - Reinstate Monica Jun 12 '15 at 22:26
  • FP numbers are logarithmically distributed. Using `abs(fval - dval) <= FLT_EPSILON/DBL_EPSILON` is a bad idea. For large values, the code is effectively `if (fval == dval)`. For small values, the code is effectively `if (true)`. A good _nearness_ comparison involves looking at the ratio of the 2 numbers with special handing for different signs and 0. – chux - Reinstate Monica Jun 12 '15 at 22:32
  • 1
    @chux: You have a point. I added a comment to my answer. Thanks. I just do not use float in my every-day work (luckily). – too honest for this site Jun 12 '15 at 23:29
1

In short, you should NOT use == to compare floating points.

for example

float i = 1.1; // or double

float j = 1.1; // or double

This argument (i==j) == true // is not always valid

for a correct comparison you should use epsilon (very small number):

(abs(i-j)<epsilon)== true // this argument is valid

Samer
  • 1,923
  • 3
  • 34
  • 54
1

The question simplifies to why do me and you have different values?

Usually, C floating point is based on a binary representation. Many compilers & hardware follow IEEE 754 binary32 and binary64. Rare machines use a decimal, base-16 or other floating point representation.

OP's machine certainly does not represent 1.1 exactly as 1.1, but to the nearest representable floating point number.

Consider the below which prints out me and you to high precision. The previous representable floating point numbers are also shown. It is easy to see me != you.

#include <math.h>
#include <stdio.h>
int main(void) {
    float me = 1.1;
    double you = 1.1;
    printf("%.50f\n", nextafterf(me,0)); // previous float value
    printf("%.50f\n", me);
    printf("%.50f\n", nextafter(you,0)); // previous double value
    printf("%.50f\n", you);

1.09999990463256835937500000000000000000000000000000
1.10000002384185791015625000000000000000000000000000
1.09999999999999986677323704498121514916420000000000
1.10000000000000008881784197001252323389053300000000

But it is more complicated: C allows code to use higher precision for intermediate calculations depending on FLT_EVAL_METHOD. So on another machine, where FLT_EVAL_METHOD==1 (evaluate all FP to double), the compare test may pass.

Comparing for exact equality is rarely used in floating point code, aside from comparison to 0.0. More often code uses an ordered compare a < b. Comparing for approximate equality involves another parameter to control how near. @R.. has a good answer on that.

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

Because you are comparing two Floating point!

Floating point comparison is not exact because of Rounding Errors. Simple values like 1.1 or 9.0 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations can change the result. Different compilers and CPU architectures store temporary results at different precisions, so results will differ depending on the details of your environment. For example:

float a = 9.0 + 16.0
double b = 25.0
if(a == b) // can be false!
if(a >= b) // can also be false!

Even

if(abs(a-b) < 0.0001) // wrong - don't do this

This is a bad way to do it because a fixed epsilon (0.0001) is chosen because it “looks small”, could actually be way too large when the numbers being compared are very small as well.

I personally use the following method, may be this will help you:

#include <iostream>     // std::cout
#include <cmath>        // std::abs
#include <algorithm>    // std::min
using namespace std;

#define MIN_NORMAL 1.17549435E-38f
#define MAX_VALUE 3.4028235E38f

bool nearlyEqual(float a, float b, float epsilon) {
    float absA = std::abs(a);
    float absB = std::abs(b);
    float diff = std::abs(a - b);

    if (a == b) {
        return true;
    } else if (a == 0 || b == 0 || diff < MIN_NORMAL) {
        return diff < (epsilon * MIN_NORMAL);
    } else {
        return diff / std::min(absA + absB, MAX_VALUE) < epsilon;
    }
}

This method passes tests for many important special cases, for different a, b and epsilon.

And don't forget to read What Every Computer Scientist Should Know About Floating-Point Arithmetic!

mazhar islam
  • 5,561
  • 3
  • 20
  • 41