# FloatingPoint equality ..

I've spent a fascinating evening and morning in the arcane depths of
floating point, specifically researching the comparison of two floating
point numbers. I pretty much understand how to do this with a combination
of 'epsilon' and 'ULPs' after reading this
<https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/&gt;
.

For example, for a off-by-one ULP comparison:

public func almostEqual(_ a: Double, _ b: Double) -> Bool {

return a == b ||

a == nextafter(b, +.greatestFiniteMagnitude) ||

a == nextafter(b, -.greatestFiniteMagnitude)

}

My question is whether Swift has a built in method that provides an 'almost
equal' comparison?

Or, asking the same question another way, what doesn't the Swift method

func isEqual(to other: Self) -> Bool
<https://developer.apple.com/documentation/swift/bool&gt;

actually do? Does it test for equality of the binary representation of
'self' and 'other' (I assume it must given no 'precision' argument) .. I
read it follows the IEEE meaning of equality but that document is not on my
bookshelf and is quite expensive!

I've spent a fascinating evening and morning in the arcane depths of floating point, specifically researching the comparison of two floating point numbers. I pretty much understand how to do this with a combination of 'epsilon' and 'ULPs' after reading this <https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/&gt;\.

For example, for a off-by-one ULP comparison:

public func almostEqual(_ a: Double, _ b: Double) -> Bool {
return a == b ||
a == nextafter(b, +.greatestFiniteMagnitude) ||
a == nextafter(b, -.greatestFiniteMagnitude)
}

My question is whether Swift has a built in method that provides an 'almost equal' comparison?

It does not. It is “trivial” to implement such a comparison (just like you do here); the difficulty is entirely in guiding users in choosing a means of comparison and tolerance appropriate to their problem.

Or, asking the same question another way, what doesn't the Swift method

func isEqual(to other: Self) -> Bool <https://developer.apple.com/documentation/swift/bool&gt;

actually do? Does it test for equality of the binary representation of 'self' and 'other' (I assume it must given no 'precision' argument) .. I read it follows the IEEE meaning of equality but that document is not on my bookshelf and is quite expensive!

isEqual implements IEEE equality, which is *not the same* as bitwise equality of representation. In particular:

1. x != x is true when x is NaN.
2. –0 == +0, but the two values have different encodings.
3. Float80 admits non-canonical “pseudo denormal” values that compare equal to a canonical value with a different encoding.
4. IEEE 754 Decimal types (not implemented in the standard library) have *many* encodings that compare equal.

– Steve

···

On Jun 29, 2017, at 2:40 PM, Gavin Eadie via swift-users <swift-users@swift.org> wrote:

I should also point out:

(a) your code can be somewhat simpler in Swift. I would probably write something along the lines of:

func almostEqual<T: FloatingPoint>(_ a: T, _ b: T) -> Bool {
return a >= b.nextDown && a <= b.nextUp
}

(b) one ULP is almost never a tolerance you want to use. It’s much too small for almost all computations, and too large for most of the remaining ones.

– Steve

You can make it even simpler with a range pattern

func almost_equal<T:FloatingPoint>(_ a:T, _ b:T) -> Bool
{
return b.nextDown ... b.nextUp ~= a
}

···

On Thu, Jun 29, 2017 at 3:05 PM, Stephen Canon via swift-users < swift-users@swift.org> wrote:

I should also point out:

(a) your code can be somewhat simpler in Swift. I would probably write
something along the lines of:

func almostEqual<T: FloatingPoint>(_ a: T, _ b: T) -> Bool {
return a >= b.nextDown && a <= b.nextUp
}

(b) one ULP is almost never a tolerance you want to use. It’s much too
small for almost all computations, and too large for most of the remaining
ones.

– Steve

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

1 Like

.. agreed but this looks too awful (and is mostly a joke!)

return a >= b.nextDown.nextDown.nextDown.nextDown && a <= b.nextUp.
nextUp.nextUp.nextUp

Thanks, friends, for your insights and info .. Gavin

···

On Thu, Jun 29, 2017 at 3:30 PM, Taylor Swift via swift-users < swift-users@swift.org> wrote:

(b) one ULP is almost never a tolerance you want to use. It’s much too
small for almost all computations, and too large for most of the remaining
ones.

– Steve

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

I'd probably do this:
precedencegroup FauxTwoPartOperatorPrecedence {
associativity: right
higherThan: BitwiseShiftPrecedence
}
public struct VaE<T> {
var value: T
var epsilon: T
}
infix operator ± : FauxTwoPartOperatorPrecedence // `±` is typed "shift-opt-=", at least with macOS's default QWERTY US keyboard layout
public func ± <T: BinaryFloatingPoint> (value: T, epsilon: T) -> VaE<T> {
return VaE(value: value, epsilon: epsilon)
}
public func == <T: BinaryFloatingPoint> (lhs: T, rhs: VaE<T>) -> Bool {
return lhs <= (rhs.value + rhs.epsilon) && lhs >= (rhs.value - rhs.epsilon)
}

0.0 == 0.0 ± 0.1 // true
1.0 == 0.0 ± 0.1 // false
-0.3 == 0.0 ± 0.5 // true

(or use something like `+-`, if you prefer your custom operators to be not quite that custom)

Hope that helps,
- Dave Sweeris

···

On Jun 29, 2017, at 2:20 PM, Gavin Eadie via swift-users <swift-users@swift.org> wrote:

.. agreed but this looks too awful (and is mostly a joke!)

return a >= b.nextDown.nextDown.nextDown.nextDown && a <= b.nextUp.nextUp.nextUp.nextUp

Thanks, friends, for your insights and info .. Gavin

On Thu, Jun 29, 2017 at 3:30 PM, Taylor Swift via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

(b) one ULP is almost never a tolerance you want to use. It’s much too small for almost all computations, and too large for most of the remaining ones.

– Steve

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users