如何在Rust中处理不精确的浮点运算结果? [英] How to deal with inexact floating point arithmetic results in Rust?

查看:584
本文介绍了如何在Rust中处理不精确的浮点运算结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在Rust中处理浮点运算?

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);
}

返回:

[-0.010000000000000009, -0.010000000000000009, 0.020000000000000018, -0.040000000000000036]

预期输出:

[-0.01, -0.01, 0.02, -0.04]

我了解发生这种情况的原因,但从未解决过.

I understand the reason for this happening but have never had to address it.

更新:

之所以发布此帖子,是因为其他语言(例如Python)的结果似乎是准确的.计划是在Rust中复制Python的方法,但是在进一步研究中,Python,numpy和pandas都以相同的方式处理数字.也就是说,仍然存在错误,但并不总是可见/显示.另一方面,Rust使这些无用之物变得显而易见,一开始令人困惑.

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.

示例:

l = [1.01, 1.02, 1.03, 1.01, 1.05]

for i in l:
    print('%.18f' % i)

打印:

1.010000000000000009
1.020000000000000018
1.030000000000000027
1.010000000000000009
1.050000000000000044

print(l)打印:

[1.01, 1.02, 1.03, 1.01, 1.05]

推荐答案

由于您知道为什么会发生这种情况,因此我假设您要格式化输出.

Since you know why this happens, I assume you want to format the output.

官方文档中一样:

精度

对于非数字类型,可以将其视为最大宽度".如果结果字符串长于此宽度,则将其截断为这么多字符,并且如果设置了这些参数,则会使用正确的fillalignmentwidth发出截断的值.

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.

有三种可能的方法来指定所需的precision:

There are three possible ways to specify the desired precision:

  1. 整数.N:

整数N本身就是精度.

一个整数或名称,后跟一个美元符号.N$:

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

使用格式参数N(必须为usize)作为精度.

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

一个星号.*:

.*表示此{...}两个格式输入关联,而不是与一个输入关联:第一个输入保持usize精度,第二个输入保持要打印的值.请注意,在这种情况下,如果使用格式字符串{<arg>:<spec>.*},则<arg>部分将引用要打印的值,并且precision必须出现在<arg>之前的输入中.

.* 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);

游乐场

但是,如果您想继续保持这种精度,则可以对结果进行四舍五入:

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

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

游乐场

另请参见:

这篇关于如何在Rust中处理不精确的浮点运算结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆