-1

I want to compare floats. I had a problem when comparing equality so I used epsilon and it was solved

inline bool isEqual(float x, float y)
{
  const float epsilon = 1e-5;
  return abs(x - y) <= epsilon * abs(x);
}

but I also want to compare other comparisons such as '>' and '<='

I have two floats = 49 but when executing f1 > f2 it returns true.

I have tried this function:

inline bool isSmallerOrEqual(float x, float y)
{
  const float epsilon = 0.01;
  return epsilon * abs(x) <= epsilon * abs(y);
}

It worked but not for all values. Any ideas ?

  • `return (x < y) || IsEqual(x, y);`. Did you try that? The values are either indeed less than, and if not, the `IsEqual()` function is called. Sounds logical to me. – PaulMcKenzie Jul 07 '19 at 00:56
  • [There is no general solution for comparing floating-point numbers.](https://stackoverflow.com/a/17047601/298225). Using an “epsilon,” that is, allowing a tolerance, reduces false negatives (occasions when the comparison reports false for numbers computed with floating-point arithmetic that would satisfy the relation if they had been computed with real number arithmetic) at the expense of increasing false positives (occasions when the comparison reports true for numbers that would not satisfy the relation). Whether and how much an application can tolerate this is application-specific. – Eric Postpischil Jul 07 '19 at 01:04
  • You have not given any context. What is the potential error in the numbers you have calculated? (This depends on the calculations performed and the values involved, and it can range from zero to infinity, which is another reason there is no general solution.) What is the harm caused if your test reports a false negative? What is the harm caused if your test reports a false positive? – Eric Postpischil Jul 07 '19 at 01:07
  • Possible duplicate of [Is there a way to properly compare if 1 float value is larger / smaller than another?](https://stackoverflow.com/questions/32733754/is-there-a-way-to-properly-compare-if-1-float-value-is-larger-smaller-than-ano) – JaMiT Jul 07 '19 at 02:17
  • Note that this “nearly equals” function has the unintuitive property that “a nearly equals b” and “b nearly equals c” can both be true, but “a nearly equals c” can be false. – Pete Becker Jul 07 '19 at 02:31
  • Why are you multiplying epsilon by the absolute value of x in `isEqual`? That completely defeats the purpose of an epsilonEquals function. – vandench Jul 07 '19 at 03:57
  • @PeteBecker: That undesirable property applies to the majority of "nearly equals" functions. The other alternative is to develop equivalence classes (buckets) but then two values straddling a class boundary can be arbitrarily close yet not considered equal. – Ben Voigt Jul 07 '19 at 05:05
  • @Eric: I think [this](https://stackoverflow.com/a/77735/103167) is the oldest canonical question having answers explaining that. – Ben Voigt Jul 07 '19 at 05:08
  • 1
    @vandench — that multiplication scales the epsilon to better match the magnitude of the numbers being compared. Think of it as checking that the values are within .01%, for example. – Pete Becker Jul 07 '19 at 17:23
  • @PeteBecker The whole point of epsilonEquals is to handle _small_ errors in floating point arithmetic. If we were to take this function and apply it to 2 vectors (such as in a game), and x had a component at 1,000,000, those 2 positions would be equal if they were 10 units off from each other using this poorly written function. If this were Minecraft that would mean that 2 players would be in the same position if they were 10 blocks away from each other. The cumulative error in FP math is generally very small, less than an entire whole number. – vandench Jul 07 '19 at 20:32
  • @vandench -- the magnitude of computational errors depends **directly** on the values being computed. The error is in the low bits of the mantissa; having a large exponent doesn't make that error in the low bits smaller. Multiplying a value by 2^20 leaves the same bit error in the mantissa, but the absolute error has been enlarged by a factor of 2^20. – Pete Becker Jul 07 '19 at 20:47
  • @PeteBecker if you’re multiplying your number by 2**20 you should be using a double precision fp number, in which case the error in the mantissa is even smaller, once again nullifying the idea that you should scale your epsilon. – vandench Jul 07 '19 at 20:58

2 Answers2

0

First, your isEquals function may be wrong, you're using the relative epsilon version. This version is works better with extremely large numbers, but breaks down when using extremely small numbers. The other version would be to use absolute epsilon. This version works well with small numbers (including extremely small numbers), but breaks down with extremely large numbers.

inline bool epsilonEquals(const float x, const float y, const float epsilon = 1E-5f)
{
    return abs(x - y) <= epsilon;
}

Second, calling it isEquals is inaccurate, the function is generally known as Epsilon Equals because it doesn't validate that 2 numbers are equal, it validates that they are reasonably close to each other within a small margin of error (epsilon).

Third, if you want to check that 2 numbers are less than or equal to each other then you generally don't need or even want an epsilon equals function involved, doing so only increases the likelihood of false positive. If you do want to use epsilon comparison you can take advantage of paulmckenzie's method:

inline bool epsilonLessThanOrEqualTo(const float x, const float y, const float epsilon = 1E-5f)
{
    return x <= y || epsilonEquals(x, y, epsilon);
}

If you want to have an epsilon not-equals method you can simply check that the absolute difference between the 2 numbers is larger than epsilon.

vandench
  • 1,973
  • 3
  • 19
  • 28
  • It is quite common to use a tolerance which is proportional to the magnitude of the quantities compared. – Ben Voigt Jul 07 '19 at 05:02
-1

I was trying to add float values (all have one precision) through for loop, and then compare the result value with a normal declared float. But I was not getting the answers right.

I solved it by converting the floats to int by multiplying each with 10, then compare it with value*10

  • 1
    This (AKA Fixed Point Arithmetic) is a really good solution to your problem, but not so good a Stack Overflow answer. Part of that is because the question's not well specified. I recommend editing the question to add in the fact that you only need one digit of precision and then this answer will make good sense with respect to the question. – user4581301 Jul 07 '19 at 01:47