How to deal with inexact floating point arithmetic results in Rust? [closed]

牧云@^-^@ 提交于 2020-05-14 13:52:08

问题


How to deal with floating point arithmetic in Rust?

For example:

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]

回答1:


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 and width 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:

  1. An integer .N:

    the integer N itself is the precision.

  2. An integer or name followed by dollar sign .N$:

    use format argument N (which must be a usize) as the precision.

  3. An asterisk .*:

    .* means that this {...} is associated with two format inputs rather than one: the first input holds the usize 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 the precision 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);

Playground

However, if you want to continue with this precision, you may round the results:

.map(|x| (x * 100.0).round() / 100.0)

Playground


See also:

  • How does one round a floating point number to a specified number of digits?


来源:https://stackoverflow.com/questions/50361151/how-to-deal-with-inexact-floating-point-arithmetic-results-in-rust

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!