将浮点和从 Python 重写为 Rust

rewriting a floating point sum from Python to Rust

我一直在尝试重写下面的代码以求和浮点数,同时最大限度地减少舍入误差,但我发现在 Rust 中很难做到。任何建议将不胜感激。我附上我的非工作 Rust 尝试

def msum(iterable):
    "Full precision summation using multiple floats for intermediate values"
    # Rounded x+y stored in hi with the round-off stored in lo.  Together
    # hi+lo are exactly equal to x+y.  The inner loop applies hi/lo summation
    # to each partial so that the list of partial sums remains exact.
    # Depends on IEEE-754 arithmetic guarantees.  See proof of correctness at:
    #www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps

    partials = []               # sorted, non-overlapping partial sums
    for x in iterable:
        i = 0
        for y in partials:
            if abs(x) < abs(y):
                x, y = y, x
            hi = x + y
            lo = y - (hi - x)
            if lo:
                partials[i] = lo
                i += 1
            x = hi
        partials[i:] = [x]
    return sum(partials, 0.0)

下面的代码是我目前在 Rust 中的代码,但它还不能工作

fn inexact_sum(v: &Vec<f64>) -> f64 {
    let mut partials: Vec<f64> = vec![];
    for x in v {

        let mut i: usize = 0;
        let mut hi: f64;
        let mut lo: f64;

        for y in partials.clone().iter() {
            hi = x + y;
            lo = if x.abs() < y.abs() {
                y - (hi - x)
            } else {
                x - (hi - y)
            };
            if lo != 0.0_f64 {
                partials[i] = lo;
                i += 1;
            }
            let x = hi;
            println!("x = {}, y = {}", x, y);
        }
        partials.truncate(i);
        partials.push(hi);
    }
    partials.iter().fold(0.0_f64, |a, b| a + b)
}

编辑:仔细想想,确实,编译器给我的错误error: use of possibly uninitialized variable: `hi`确实有用。我应该多注意它。关键是第一次循环根本没有执行,所以 hi 没有被初始化。因此,如果我将 partials.push(hi); 更改为 partials.push(*x);,代码会编译并运行,但不会给出正确的答案。

这是您要找的吗?我认为您并不是要克隆 partials 数组,而是发现您需要这样做才能满足借用检查器的要求;如果您尝试使用代码:

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]

我通过在数组中使用索引来解决这个问题:

for j in 0..partials.len() {
    let mut y = partials[j];

那么你就不会在外循环中每次都克隆整个部分数组!由于 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));
}

Playpen