3

For example, say you have a class Point which has floating point components. It's tempting to overload the equality operator so you can do something like

a = Point(1.1, 2.2)
b = Point(3.3, 6.6)
b /= 3
a == b // should always hold true

This could be achieved through an expression like abs(a-b) < epsilon. Is there any particular reason not to do something like this?

2

1 Answer 1

12

No. Never. Don't. Under any and all Circumstances.

  • Not because you could not have a fuzzy equality operation.
  • Not because you shouldn't make it easier to work with floats.
  • Not because you couldn't overload the operator.

Then why?

Because it won't work...

But heck, let's live dangerously and presume that it will work.

Let's define equality: if two floats are within some delta of each other they are equal.

Let's consider these numbers:

    A = 2.0000000005
    B = 2.0000000000
    C = 1.9999999995
    D = 1.9999999990
    E = 1.9999999985

and assume that delta is:

    Delta = 0.0000000005

So:

(a)==(b) => absolute(a-b) <= delta;

== | A | B | C | D | E
 A | T | T | F | F | F
 B | T | T | T | F | F
 C | F | T | T | T | F
 D | F | F | T | T | T
 E | F | F | F | T | T

... that is not equality.

This will work: A == B && B == C

This won't work: B == A && A == C nor B == C && C == A

Try debugging that... what a nightmare. Code that works 1/3 of the time, or alternately works 2/3 of the time depending on what your desired outcome is.

Even worse: A == B && B == C && C == D && D == E is the path in which this expression could be true, and it's not even something you would want to hold true A - E == 0.0000000020 that is four times larger than delta.

Not only would this code not work, it would be dreadful to try and debug.

Expectations

Equality is a well defined property. It's transitive, it's commutative, it's reflexive. These qualities provide hugely powerful guarantees. They allow you to substitute one value for another should they compare equal, and many powerful algorithms require that property.

This approximation does not provide those guarantees. Just because they compare equal does not mean that they can be substituted. This will be most apparent with discontinuous functions, where even a small difference can hugely affect the outcome.

If you conflate these two definitions, you are introducing a time bomb bug. Later someone is going to presume that equality means equality, not this approximate equality. They will implement an algorithm that needs the properties equality provides, and it will randomly fail in novel and interesting ways, and worse it will occasionally work for all the wrong reasons.

Define it for what it is

If you need an approximate equality, go ahead and define it. Just define it for what it is.

Something like similar(a, b) or if you have access to it ~== would perhaps work (depending on language conventions).

4
  • This answer is ok (+1), but IMHO just a long-winded way of pointing out a POLA violation.
    – Doc Brown
    Aug 26, 2019 at 6:10
  • 1
    But when something seems to be a good idea you may need a long-winded explanation when it's not.
    – gnasher729
    Aug 26, 2019 at 7:37
  • @DocBrown, Riad's comment on my question was good enough for me to understand why it's a bad idea, but this answer provided exceptional explanation and examples that helped me further understand the repercussions of conflating equals with approximately equals. I definitely welcome long-winded answers that give greater context and help with understanding. Aug 26, 2019 at 18:04
  • 1
    I do agree with @DocBrown that I could have pointed out the core issue with a single line and then further expounded by example. I was not as clear in the answer as I could have been.
    – Kain0_0
    Aug 26, 2019 at 23:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.