Search code examples
juliafloating-accuracyrounding-error

Modulus statement result differ between Julia and Matlab – best practice for avoiding rounding errors when working with floats in Julia?


I’m writing a Julia program where I have a Float64 variable (val) that needs to meet the following criteria:

(val – m) % s == 0

m and s are numbers stored as strings, for example: m = "0.00010000" and s = "0.00010000".

If I do the following calculation in Matlab:

val = 0.2383;
m = "0.00010000";
s = "0.00010000";
result = mod((val - str2double(m)), str2double(s)) == 0;
disp( result )

the answer gets evaluated as true. I.e the (val – m) % s == 0 criteria is fulfilled.

However, when I try to do the same thing in my Julia implementation of the same program I run into issues:

val = 0.2383;
m = "0.00010000";
s = "0.00010000";
result = ((val - parse( Float64, m )) % parse( Float64, s )) == 0;
println( result ) 

The Julia version of the same calculation now becomes false.

This is likely due to floating-point rounding errors, the result of val – parse(Float64, m) in Julia is for example 0.23820000000000002 which is not exactly divisible by 0.0001.

So my question is: in Julia, how can I adjust my calculations such that the criteria is met like it is in the Matlab code? Can I parse my val/m/s variables differently to avoid rounding issues?

Ideally, due to speed concerns, I would like to avoid using packages such as “Decimals” and stick to fast variable types.


Solution

  • This is not a language issue but rather how your CPU works with floating point arithmetic. Numbers being rational in 10-based system are just not rational in the binary system.

    Perhaps Matlab provides some implementation that does the rounding without telling the user about it. But always the rounding is another separate operation.

    In Julia you can do:

    julia> isapprox( ((val - parse( Float64, m )) % parse( Float64, s )), 0, atol=eps())
    true
    

    Note that there is also an operator but its default tolerance seems to be to narrow for your example. Try typing ?≈ in Julia console for more details.