How to deal with floating point arithmetic in Rust?
fn main() {
let vector = vec![1.01_f64, 1.02, 1.03, 1.01, 1.05];
let difference: Vec<f64> = vector.windows(2).map(|slice| slice[0] - slice[1]).collect();
println!("{:?}", difference);
}
Returns:
[-0.010000000000000009, -0.010000000000000009, 0.020000000000000018, -0.040000000000000036]
Expected output:
[-0.01, -0.01, 0.02, -0.04]
I understand the reason for this happening but have never had to address it.
Update:
This post came about because results in other languages such as Python appeared to be exact. The plan was to replicate Python's approach in Rust however upon further investigation, Python, numpy and pandas all deal with numbers in the same way. That is, the inaccuracies are still present however not always visible/shown. Rust on the other hand made these innacuracies obvious which was confusing at first.
Example:
l = [1.01, 1.02, 1.03, 1.01, 1.05]
for i in l:
print('%.18f' % i)
Prints:
1.010000000000000009
1.020000000000000018
1.030000000000000027
1.010000000000000009
1.050000000000000044
whereas print(l)
prints:
[1.01, 1.02, 1.03, 1.01, 1.05]
Since you know why this happens, I assume you want to format the output.
As in the official docs:
Precision
For non-numeric types, this can be considered a "maximum width". If the resulting string is longer than this width, then it is truncated down to this many characters and that truncated value is emitted with proper
fill
,alignment
andwidth
if those parameters are set.For integral types, this is ignored.
For floating-point types, this indicates how many digits after the decimal point should be printed.
There are three possible ways to specify the desired
precision
:
An integer
.N
:the integer
N
itself is the precision.An integer or name followed by dollar sign
.N$
:use format argument
N
(which must be ausize
) as the precision.An asterisk
.*
:
.*
means that this{...}
is associated with two format inputs rather than one: the first input holds theusize
precision, and the second holds the value to print. Note that in this case, if one uses the format string{<arg>:<spec>.*}
, then the<arg>
part refers to the value to print, and theprecision
must come in the input preceding<arg>
.
So in your case, one of those does the job:
println!("{0:.2?}", difference);
println!("{1:.0$?}", 2, difference);
println!("{:.*?}", 2, difference);
println!("{1:.*?}", 2, difference);
println!("{number:.prec$?}", prec = 2, number = difference);
However, if you want to continue with this precision, you may round the results:
.map(|x| (x * 100.0).round() / 100.0)
See also: