JavaScript Rounding Errors Inherited by Elm

This probably came up, but I would like to ask (again):

JavaScript has rounding problems. For example:

0.1 * 0.2 // == 0.020000000000000004

Looks like Elm inherits those problems. Is this intentional or are there plans to correct those errors at some point?

Thank you.

This isn’t just JavaScript problem, but general problem with all programming languages, as it comes from how computers represent floating point numbers.

Fixing this for all floating point calculations is not feasible as it would slow down calculations a lot.

Solution here is to use separate Decimal type in those calculations which require exact math. There seems to be at least prikhi/decimal package for Elm which does this. (I havn’t used this, I just searched for Decimal packages in Elm.)

4 Likes

This is the result of floating point numbers.

Here is one of many sites that explain why this happens:

https://floating-point-gui.de/basic/

2 Likes

As mentioned by other commenters, this is common among all languages that use IEEE 754 floating-point numbers—that is to say, all languages that run on modern computers.

The reason for this is that IEEE 754 has been implemented at the hardware level, right down to the tricky NaN /= NaN behavior. That’s basically why we can’t fix it: creating an alternate system means skipping over all those hardware optimizations using this system. In effect, to get away from these issues we’d either need to create a much slower numeric computation stack or make our own hardware. Neither of those is particularly tenable!

1 Like

IEEE 754 standard actually does include decimal floating-point types since 2008 (fairly new addition, given that original standard is from 1985), and some hardware (e.g. IBM Power processors) does support them - but unfortunately not the common PC processors from Intel or AMD.

Some discussion here: Why isn’t decimal floating-point (DFP) from the IEEE 754-2008 already implemented in hardware of all modern CPUs by now?.

4 Likes

Whoah, that’s neat! Thanks for adding that.

As people have mentioned, this is a problem with floating point. That said, it isn’t unique to floating point either. Even if you do math with a decimal library you’ll get rounding errors. Consider 10 * (2/3) = 0.6666666...and forever except we can’t represent an infinite number of 6’s so it gets rounded to something like 0.6666667.

Thank you all for the answers.

I understand the issue better now.

I think a simpler solution than switching to a decimal or rational type (which would also be much lower performance than IEEE-754 doubles) is to use plain Float values and use something like myrho/elm-round to control the number of decimal places used when displaying those values.

You’ll also need to avoid trying to compare two Float values for equality using == - either compare within some small tolerance, or (even better) avoid equality comparisons entirely. It can be very hard to come up with a good tolerance value, and speaking as someone who’s spent most of their career working on scientific/numerical code I find that it’s usually possible to restructure the code in a way that doesn’t need equality checks (and that’s usually a cleaner and more robust solution).

3 Likes

There are a couple packages in the repo for arbitrary-precision. You could explore them if you like. Search for “arbitrary precision”, however that sort of thing is not performant in the way you probably want. Have fun!

This is why elm-test suggests the assertions on floating point “equality” are given with some tolerance.