Comparing Same Float Values In C [duplicate]

纵然是瞬间 提交于 2019-11-29 02:23:52

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.

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.

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

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

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

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!