What is the best way to test if one floating point number is an integer multiple of another floating number? e.g. I want this to return true for 5.5 / 0.5, and false for 5.5 / 0.6.
Naively I would expect to do this by testing for remainder 0 after division using %, i.e.
0.2 % 0.1 == 0.0 true
0.21 % 0.1 == 0.0 false
This works on some numbers, but fails on others, presumably due to the magic of floating point precision:
0.3 % 0.1 = 0.09999999999999998 # should be 0.0
What’s the most accurate, and/or simplest, way to test this?
The moment you represent your numbers in floating point, it’s already too late. The number 1/10 cannot be represented in binary floating point with any finite precision for the same reason that 1/3 cannot be represented in any finite precision decimal value (they’re both just infinitely repeating fractions in their respective bases).
You can use Rational numbers, which will give you the exact right answer.
But if you’re somehow stuck with floating-point inputs, then you’re going to have to make up your own tolerances. For example, you could check something like:
julia> check(a, b) = isapprox(round(b / a) * a, b)
check (generic function with 1 method)
julia> check(0.1, 0.2)
true
julia> check(0.1, 0.25)
false
julia> check(0.1, 0.3)
true
Of course, this has edge cases too:
julia> check(0.1, 0.0) # should be true, and is
true
julia> check(0.1, 1e-16) # what should this be? Not obvious...
false
julia> check(0.1 + 1e-16, 0.2) # seems like this should match the one above...
true
What is preventing you from taking exact rational inputs if you actually want exact numerical results here?
Strictly speaking nothing is preventing me from taking exact rational inputs, but I was just interested in the best way to handle this problem given an arbitrary collection of floating-point numbers.
For the specific example I have in mind though I’m taking elements in a range object e.g. 0:0.01:1 and testing them with another number, so this would be amenable to rationals.