Create correct result with operation over floats

I'm making a calculator in rust, and occasionally when I try to multiply two floats with it, it gives a result like this
image
I could truncate the number, but in other calculation scenarios where it needs to go to that decimal point, that extra precision might be required, eg if I enter into my calculator 1.2000000000002. What would be the best way to detect and remove these small [annoying] inaccuracies?

Don't use floats for everything that needs arbitrary precision. That's the only way.

3 Likes

I suggest you look into using one of those ‘decimal’ search // Lib.rs (if you want "absolute" precision there are also some "fraction"/"rational" crates)

1 Like

Those inaccuracies are inherent in the way floating point numbers work. Internally, they calculate everything in base 2. This means that any divisor with a prime factor other than 2 must be approximated.

Decimals have the same problem: Fractions with a denominator of 3 or 7 can't be represented exactly.
They end up in an infinite sequence of digits that must be truncated at some point, producing an approximation.

The only way to avoid these errors completely is to store the numerator and denominator separately as integers. This isn't used very often because it's quite inefficient for most computations.

To get around this, you can use the num-rational crate.

3 Likes

First you have to figure out exactly what you're trying to support precisely. For example, the rational numbers approach handles some of it, but that's not enough if you want roots to also be precise, because they're irrational and don't give perfect results in floats either

let x = 2.0_f64.sqrt() * 3.0_f64.sqrt();
dbg!(x * x); // 6.000000000000001

You could solve that with more complicated systems, like doing symbolic manipulation and encoding simplifications.

Or you could decide that's too much work, and just track an interval for the result, and be sure to only show as many decimals as you can be confident about.

Here's a fun little page if you want to experiment with why you get the numbers you do from floating-point: Float Toy

1 Like

The f64 floating point type has about 16 digits of precision. If you round to 15 digits you get the expected result.
E.g: println! ("{:.15}", 3.0*0.4);
prints 1.200000000000000
For a nicer result you may want to remove the trailing zeroes.