Comparing Same Float Values In C [duplicate]

2020-02-09 14:29发布

问题:

This question already has answers here:
Closed 7 years ago.

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.

回答1:

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.


回答2:

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.



回答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


回答4:

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".



回答5:

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;
   }
 }


回答6:

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.



回答7:

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.