将Python中的浮点和重写为Rust

将Python中的浮点和重写为Rust,rust,rounding,floating,Rust,Rounding,Floating,我一直在尝试重写下面的代码,以便在最小化舍入误差的同时求和浮点数,但我发现在Rust中很难做到这一点。如有任何建议,将不胜感激。我附上我的非工作防锈剂 def msum(可编辑): “使用中间值的多个浮点进行全精度求和” #四舍五入x+y存储在hi中,四舍五入存储在lo中。在一起 #hi+lo正好等于x+y。内部循环应用hi/lo求和 #对于每个部分,使部分和列表保持精确。 #取决于IEEE-754算术保证。请参见以下网址的正确性证明: #www-2.cs.cmu.edu/afs/cs/proj

我一直在尝试重写下面的代码,以便在最小化舍入误差的同时求和浮点数,但我发现在Rust中很难做到这一点。如有任何建议,将不胜感激。我附上我的非工作防锈剂

def msum(可编辑):
“使用中间值的多个浮点进行全精度求和”
#四舍五入x+y存储在hi中,四舍五入存储在lo中。在一起
#hi+lo正好等于x+y。内部循环应用hi/lo求和
#对于每个部分,使部分和列表保持精确。
#取决于IEEE-754算术保证。请参见以下网址的正确性证明:
#www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-算术.ps
分部=[]#排序的、不重叠的分部和
对于iterable中的x:
i=0
对于y部分:
如果abs(x)
下面的代码是我到目前为止在Rust中的代码,但它还没有工作

fn不精确和(v:&Vec)->f64{
设mut partials:Vec=Vec![];
对于v中的x{
设muti:usize=0;
让mut hi:f64;
让mut lo:f64;
对于partials.clone().iter()中的y{
hi=x+y;
lo=如果x.abs()小于y.abs()){
y-(hi-x)
}否则{
x-(hi-y)
};
如果lo!=0.0_f64{
分部[i]=lo;
i+=1;
}
设x=hi;
println!(“x={},y={},x,y);
}
截断(i);
推(hi);
}
partials.iter()折叠(0.0_f64,| a,b | a+b)
}

编辑:再想一想,实际上,编译器给我的错误
错误:使用可能未初始化的变量:`hi`
,确实很有用。我应该多加注意的。关键是第一次循环根本不执行,所以hi不会被初始化。因此,如果我更改
partials.push(hi)
部分推送(*x)代码编译并运行,但没有给出正确的答案。

这就是您要寻找的吗?我认为您并非有意克隆
部分
数组,而是发现为了满足借用检查器的要求,您需要克隆该数组;如果您尝试使用该代码:

for y in partials.iter() {
    ...
    partials[i] = lo;
借阅检查人将投诉:

<anon>:13:17: 13:25 error: cannot borrow `partials` as mutable because it is also borrowed as immutable [E0502]
那么你就不是每次都在外循环中克隆整个部分数组了!由于可以在迭代过程中修改
partials
数组,因此首先进行克隆意味着您将得到
y
的旧值,而不是修改后的新值

use std::mem;

fn msum(v: &[f64]) -> f64 {
    let mut partials: Vec<f64> = vec![];
    for x in v {
        let mut x = *x;
        let mut i = 0;
        for j in 0..partials.len() {
            let mut y = partials[j];
            if x.abs() < y.abs() { mem::swap(&mut x, &mut y) }
            let hi = x + y;
            let lo = y - (hi - x);
            if lo != 0.0 {
                partials[i] = lo;
                i += 1;
            }
            x = hi;
        }
        partials.truncate(i);
        partials.push(x);
    }
    partials.iter().fold(0., |a, b| a + b)
}

fn main() {
    let v = vec![1.234, 1e16, 1.234, -1e16];
    println!("{}",msum(&v));
}
使用std::mem;
fn msum(v:&[f64])->f64{
设mut partials:Vec=Vec![];
对于v中的x{
设mut x=*x;
设muti=0;
对于0..partials.len()中的j{
设mut y=partials[j];
如果x.abs()

“但它还没有工作”没有帮助。它以什么方式不起作用?@Veedrac抱歉,我应该提供更多细节。在我看来,Python版本在对迭代器进行迭代时会修改迭代器。这通常被认为是不好的做法,我认为这是生锈问题的根源。无论如何,我从稳定的
rustc
中得到的错误消息是
error:使用可能未初始化的变量:`hi`[E0381]
,这很奇怪,因为
hi
是绝对初始化的,并且定义在
循环的内部
范围之外。“但它没有给出正确答案”指什么?具体点。
部分
在第一次迭代中是一个空向量;因此,内部循环将不会运行,
hi
从未设置为任何值。一般来说,即使
部分
有一些初始值,编译器也无法跟踪它(这就是为什么它说可能未初始化),并且您必须处理
部分
可能为空的情况。这似乎是可行的。你很接近。但我看不出这方面有什么不同precision@Shepmaster修正了,希望解释清楚。看起来很棒!太糟糕了,我只能投一票!
use std::mem;

fn msum(v: &[f64]) -> f64 {
    let mut partials: Vec<f64> = vec![];
    for x in v {
        let mut x = *x;
        let mut i = 0;
        for j in 0..partials.len() {
            let mut y = partials[j];
            if x.abs() < y.abs() { mem::swap(&mut x, &mut y) }
            let hi = x + y;
            let lo = y - (hi - x);
            if lo != 0.0 {
                partials[i] = lo;
                i += 1;
            }
            x = hi;
        }
        partials.truncate(i);
        partials.push(x);
    }
    partials.iter().fold(0., |a, b| a + b)
}

fn main() {
    let v = vec![1.234, 1e16, 1.234, -1e16];
    println!("{}",msum(&v));
}