Working with machine precision

If I execute 3*0.1, Julia prints the value as 0.30000000000000004. I believe the inaccuracy is caused by machine precision, but it doesn’t seem useful to me that Julia would display this. I also note that I have never encountered this kind of issue working with numbers greater than 1. What’s the cause of this issue, and what’s the best way around it?

It is hard for Julia to know that you don’t want the result printed as accurately as possible. You can use the round function if you want to show fewer digits of precision. There is also the PR https://github.com/JuliaLang/julia/pull/29249 to allow showing things in the REPL in a “compact” version which would end up being printed as:

julia> sprint(show, 0.1*3, context=:compact=>true)
"0.3"
2 Likes

Well round does only work raliable in the windows built, see this thread

This was written in the context of “I only want to see a few digits and I don’t care about exact accuracy”.

1 Like

I’d question the definition of exact accuracy - clearly, the exact solution is 0.3.

Also, 0.4 cannot be represented exactly, but (0.1 + 0.1 + 0.1) + 0.1 produces 0.4. Not quite sure where the 4e-16 has gone, as I would have assumed numerical inaccuracies would compound.

Please read through PSA: floating-point arithmetic and see if you have further questions.

2 Likes

I find it weird that executing 3/10 prints 0.3 but executing 3 * 0.1 prints 0.30000000000000004.

1 Like

I understand how floating-point arithmetic works. The examples given there demonstrate catastrophic cancellation, and the result of all the calculations is equal to eps(). The article gives this example to demonstrate that all these calculations are performed in the same way. However, the examples which I am demonstrating can’t be replicated in other languages.

Eg. (in C, what I would expect)

printf("%1.16e\n", .3);
3.0000000000000004

printf("%1.16e\n", .1 + .1 + .1);
3.0000000000000004

Eg. (in Julia)

> .3
0.3
> .1 + .1 + .1
0.30000000000000004

Have you seen http://0.30000000000000004.com/?

That seems to print 2.9999999999999999e-01 (which Julia also does with @printf):

julia> using Printf

julia> @printf "%1.16e\n" .3
2.9999999999999999e-01

Anyway, Julia uses the GRISU (or Ryu) algorithm to print the float. It guarantees that the generated strings can be parsed back to the original number while minimizing the number of digits.

And indeed:

julia> 2.9999999999999999e-01
0.3

julia> 0.3
0.3

so printing 0.3 is shorter here and thus preferable. But in the original example, 0.3 and 0.30000000000000004 are different floating point numbers and it would thus be an error to print 0.3 since it doesn’t parse back to the original number.

4 Likes

Are you sure? Cf

which is incorrect.

When working with 64-bit IEEE floats, all languages would perform these operations the same way, they may just print the results differently. Eg R would do


> z = 0.1 * 3
> z
[1] 0.3
> z - 0.3
[1] 5.551115e-17

Julia made the choice of printing floating values which are not equal differently. This is pretty much a given at this point and unlikely to change.

As for the workarounds, you can round the numbers before printing (round), or just print rounded values using the standard library (Printf.sprint & friends), or

https://github.com/JuliaIO/Formatting.jl

or some other package (there are many), use decimal arithmetic

or the built-in rational type 3//10.

1 Like

Must have missed a compile, that put me off track >.<.

This is what I was missing. I’d suggest it would be useful to add this to the floating-point PSA referenced above.