如何在Rust中处理不精确的浮点算术结果?

时间:2018-05-16 01:17:00

标签: floating-point rust precision floating-accuracy

如何在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);
}

返回:

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

预期产出:

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

我理解发生这种情况的原因,但从未必须解决这个问题。

更新

这篇文章的出现是因为其他语言(如Python)的结果似乎是准确的。计划是在Rust中复制Python的方法,但是经过进一步调查,Python,numpy和pandas都以相同的方式处理数字。也就是说,仍然存在不准确性,但并不总是可见/显示。另一方面,Rust使得这些真空显而易见,起初令人困惑。

示例:

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]

1 个答案:

答案 0 :(得分:1)

既然你知道为什么会这样,我想你想要格式化输出。

official docs

一样
  

<强>精密

     

对于非数字类型,可以将其视为“最大宽度”。如果生成的字符串长于此宽度,则会将其截断为这么多字符,并且如果设置了这些参数,则会使用适当的fillalignmentwidth发出截断值。

     

对于整数类型,将忽略它。

     

对于浮点类型,这表示应打印小数点后的位数。

     

有三种方法可以指定所需的precision

     
      
  1. 整数.N

         

    整数N本身就是精度。

  2.   
  3. 整数或名称后跟美元符号.N$

         

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

  4.   
  5. 星号.*

         

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

  6.   

所以在你的情况下,其中一个人完成了这项任务:

println!("{0:.2?}", difference);
println!("{1:.0$?}", 2, difference);
println!("{:.*?}", 2, difference);
println!("{1:.*?}", 2, difference);
println!("{number:.prec$?}", prec = 2, number = difference);

Playground

但是,如果您想继续使用此精度,可以对结果进行舍入:

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

Playground

另见: