8

Possible Duplicate:
strange output in comparison of float with float literal

When I am trying to compare 2 same float values it doesn't print "equal values" in the following code :

void main()
{
    float a = 0.7;
    clrscr();
    if (a < 0.7)
        printf("value :  %f",a);
    else if (a == 0.7)
        printf("equal values");
    else
        printf("hello");
    getch();
}

Thanks in advance.

Community
  • 1
  • 1
gursahib.singh.sahni
  • 1,559
  • 3
  • 26
  • 51
  • 2
    `0.7` is a `double` value, `0.7f` is a `float`. – AusCBloke Mar 24 '12 at 09:53
  • Many duplicates, e.g. [strange output in comparision of float with float literal](http://stackoverflow.com/questions/1839422/strange-output-in-comparision-of-float-with-float-literal) and [Floating point issue in C](http://stackoverflow.com/questions/3916439/floating-point-issue-in-c) – Paul R Mar 24 '12 at 10:00
  • 2
    there should be a float vs double tag on SO simply for those questions :) – hochl Mar 24 '12 at 10:06

7 Answers7

34

While many people will tell you to always compare floating point numbers with an epsilon (and it's usually a good idea, though it should be a percentage of the values being compared rather than a fixed value), that's not actually necessary here since you're using constants.

Your specific problem here is that:

float a = 0.7;

uses the double constant 0.7 to create a single precision number (losing some precision) while:

if (a == 0.7)

will compare two double precision numbers (a is promoted first).

The precision that was lost when turning the double 0.7 into the float a is not regained when promoting a back to a double.

If you change all those 0.7 values to 0.7f (to force float rather than double), or if you just make a a double, it will work fine - I rarely use float nowadays unless I have a massive array of them and need to save space.

You can see this in action with:

#include <stdio.h>
int main (void){
    float f = 0.7;    // double converted to float
    double d1 = 0.7;  // double kept as double
    double d2 = f;    // float converted back to double

    printf ("double:            %.30f\n", d1);
    printf ("double from float: %.30f\n", d2);

    return 0;
}

which will output something like (slightly modified to show difference):

double:            0.6999999|99999999955591079014994
double from float: 0.6999999|88079071044921875000000
                            \_ different beyond here.
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Thanks for writing an answer that does not suggest an epsilon. This blog post I wrote some time ago has more examples of behaviors that may be surprising. http://blog.frama-c.com/index.php?post/2011/11/08/Floating-point-quiz – Pascal Cuoq Mar 24 '12 at 10:00
  • The epsilon method appears straightforward but is actually quite complex in that the epsilon chosen should be a function of the exponent of the value being compared (a vector of constants, one for each possible exponent is one solution). In addition as you approach the extreme values of the exponent epsilon becomes less and less useful as its value approaches that of the value being compared with. – Olof Forshell Mar 27 '12 at 13:44
4

Floating point number are not what you think they are: here are two sources with more information: What Every Computer Scientist Should Know About Floating-Point Arithmetic and The Floating-Point Guide.

The short answer is that due to the way floating point numbers are represented, you cannot do basic comparison or arithmetic and expect it to work.

Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
3

You are comparing a single-precision approximation of 0.7 with a double-precision approximation. To get the expected output you should use:

if(a == 0.7f) // check a is exactly 0.7f

Note that due to representation and rounding errors it may be very unlikely to ever get exactly 0.7f from any operation. In general you should check if fabs(a-0.7) is sufficiently close to 0.

Don't forget that the exact value of 0.7f is not really 0.7, but slightly lower:

0.7f = 0.699999988079071044921875

The exact value of the double precision representation of 0.7 is a better approximation, but still not exactly 0.7:

0.7d = 0.6999999999999999555910790149937383830547332763671875
Joni
  • 108,737
  • 14
  • 143
  • 193
  • why does it not work with 0.5f ? 0.5 = .1 ; thats it and its mantissa also fits in the single precision floating format. – SpawN Jan 26 '22 at 06:15
2

a is a float; 0.7 is a value of type double.

The comparison between the two requires a conversion. The compiler will convert the float value to a double value ... and the value resulting from converting a float to a double is not the same as the value resulting from the compiler converting a string of text (the source code) to a double.

But don't ever compare floating point values (float, double, or long double) with ==.

You might like to read "What Every Programmer Should Know About Floating-Point Arithmetic".

pmg
  • 106,608
  • 13
  • 126
  • 198
0

The lack of absolute precision in floats makes it more difficult to do trivial comparisons than for integers. See this page on comparing floats in C. In particular, one code snippet lifted from there exhibits a 'workaround' to this issue:

bool AlmostEqual2sComplement(float A, float B, int maxUlps)
{
    // Make sure maxUlps is non-negative and small enough that the
    // default NAN won't compare as equal to anything.
    assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
    int aInt = *(int*)&A;
    // Make aInt lexicographically ordered as a twos-complement int
    if (aInt < 0)
        aInt = 0x80000000 - aInt;
    // Make bInt lexicographically ordered as a twos-complement int
    int bInt = *(int*)&B;
    if (bInt < 0)
        bInt = 0x80000000 - bInt;
    int intDiff = abs(aInt - bInt);
    if (intDiff <= maxUlps)
        return true;
    return false;
}

A simple and common workaround is to provide an epsilon with code like so:

if (fabs(result - expectedResult) < 0.00001)

This essentially checks the difference between the values is within a threshold. See the linked article as to why this is not always optimal though :)

Another article is pretty much the de facto standard of what is linked to when people ask about floats on SO.

Mike Kwan
  • 24,123
  • 12
  • 63
  • 96
  • 1
    There is no such thing as "lack of absolute precision in floats." Their precision is absolute and the values are exact. The problem is that they are based on base 2 arithmetic and we normally use base 10. Base 10 values may or may not have an exact equivalent in base 2 and vice versa. 0.5 and 10.125 are examples of exact equivalents. 0.3 and 11.6 examples of when there is no equivalent. – Olof Forshell Mar 27 '12 at 13:53
0

Floating point numbers must not be compared with the "==" operator.

Instead of comparing float numbers with the "==" operator, you can use a function like this one :

 //compares if the float f1 is equal with f2 and returns 1 if true and 0 if false
 int compare_float(float f1, float f2)
 {
  float precision = 0.00001;
  if (((f1 - precision) < f2) && 
      ((f1 + precision) > f2))
   {
    return 1;
   }
  else
   {
    return 0;
   }
 }
aleroot
  • 71,077
  • 30
  • 176
  • 213
-2

if you need to compare a with 0.7 than

if( fabs(a-0.7) < 0.00001 )
  //your code

here 0.00001 can be changed to less (like 0.00000001) or more (like 0.0001) > It depends on the precision you need.

Azad Salam
  • 146
  • 7
  • 2
    You need to get the absolute value of the result of the subtraction result or the epsilon only grows one way. – Mike Kwan Mar 24 '12 at 09:48