Some time ago I worked on a proofofconcept which used a typesafe 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.
My test looked something like this:
1 2 3 4 5 6 7 8 9 

Looks reasonable, doesn’t it? The expected
result is in meters because it’s the base distance type. However this test fails:
1


Here’s the conversion in lldb
where we can see that the values aren’t represented exactly:
1 2 3 4 5 6 7 8 9 10 11 

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 floatingpoint numbers without an explicit accuracy threshold (epsilon):
1 2 3 4 5 6 7 8 9 10 11 

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!
Again, this is a dirty hack which may not work in your situation. I recommend this article for many more details about floatingpoint numbers in swift: https://www.jessesquires.com/blog/floatingpointswiftulpandepsilon/.