2016-03-15 52 views
2

我一直在試圖重寫下面的代碼來總結浮點數,同時最小化舍入錯誤,但我發現在Rust中很難做到這一點。任何建議將不勝感激。我附上我的非工作鏽嘗試重寫浮點數從Python到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) 

下面的代碼是什麼,我有鏽,到目前爲止,但它不工作尚未

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`確實有用。我應該更多地關注它。重點是第一次循環根本不執行,所以嗨不會被初始化。因此,如果我將partials.push(hi);更改爲partials.push(*x);,代碼將編譯並運行,但它不能給出正確的答案。

+1

「但它不工作呢。」 是無益的。它以什麼方式不起作用? – Veedrac

+0

@Veedrac對不起,我應該提供更多的細節。在我看來,Python版本在遍歷它時修改了一個迭代器。這通常被認爲是不好的做法,我認爲這是Rust的一個問題來源。無論如何,我用穩定的'rustc'得到的錯誤信息是''錯誤:使用可能未初始化的變量:'hi' [E0381]'',這很奇怪,因爲'hi'已經被初始化並且被定義在範圍之外內部for循環。 –

+1

「但它沒有給出正確答案」是指什麼?請明確點*。 – Veedrac

回答

4

這是你在找什麼?我想你並不是想要克隆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

+0

@Shepmaster修正,希望現在解釋清楚。 – Djzin

+0

看起來不錯!太糟糕了,我只有一個upvote給! – Shepmaster