Some time ago I worked on a proof-of-concept which used a type-safe units conversion library in swift (that had been before Foundation introduced their own units support). The library had measurements composed of a Double amount and a unit, e.g. “1.5 meters”. To compare measurements in tests with XCTAssertEqual, it’s necessary to conform to Equatable and implement the == function. But how do you specify the accuracy to compare doubles in this case?
Warning: this is a quick and dirty hack that shouldn’t really be used in production. Try to come up with a better design for your code to avoid it if possible.
Here’s the conversion in lldb where we can see that the values aren’t represented exactly:
1234567891011
// 200.5 centimeters = 2.005 meters(lldb)p200.5/100(Double)$R0=2.0049999999999999// 500 inches = 12.7 meters(lldb)p500*0.0254(Double)$R2=12.699999999999999// the sum should be 14.705 meters(lldb)p$R0+$R2(Double)$R4=14.704999999999998
The problem here is that == provided by Equatable accepts only the two parameters to compare, we can’t add another one for accuracy. So I came up with this quick hack to compare floating-point numbers without an explicit accuracy threshold (epsilon):
The trick here is that one ulp of a Double defines the distance to the next representable Double value, so we can compare the left and right values directly or compare one previous and one next left value with the right value. The above test now passes!