I'm making a calculator in rust, and occasionally when I try to multiply two floats with it, it gives a result like this
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.
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)
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.
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
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.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.