簡體   English   中英

Rust 通用 linspace function

[英]Rust generic linspace function

我正在嘗試實現一個通用的 function linspace:

pub fn linspace<T> (x0: T, xend: T, n: usize) -> Vec<T>
    where
        T: Sub<Output = T>
        + Add<Output = T>
        + Div<Output = T>
        + Clone
{

    let dx = (xend - x0) / ((n - 1) as T);

    let mut x = vec![x0; n];

    for i in 1..n {
        x[i] = x[i - 1] + dx;
    }

    x
}

到目前為止,我已經發現T必須實現SubAddDivClone ,但現在我遇到了n as T語句的問題。

non-primitive cast: `usize` as `T`
let dx = (xend - x0) / ((n - 1) as T);
   |                   ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object

我知道 num crate,但我試圖在沒有外部 crate 的情況下實現這一點。 有解決方法嗎? 謝謝!

如果您想堅持標准庫特征,您將需要使用TryInto ,並處理請求的轉換可能會失敗的事實,因為數字類型可能小於usize 這個版本的程序,添加了一些邊界和.clone() ,編譯:

use core::ops::Add;
use core::ops::Div;
use core::ops::Sub;
use std::fmt::Debug;

pub fn linspace<T>(x0: T, xend: T, n: usize) -> Vec<T>
where
    T: Sub<Output = T> + Add<Output = T> + Div<Output = T> + Clone + Debug,
    usize: TryInto<T>,
    <usize as TryInto<T>>::Error: Debug,
{
    let segments: T = (n - 1)
        .try_into()
        .expect("requested number of elements did not fit into T");
    let dx = (xend - x0.clone()) / segments;

    let mut x = vec![x0; n];

    for i in 1..n {
        x[i] = x[i - 1].clone() + dx.clone();
    }

    x
}

如果給定一個太大的n ,它會恐慌,例如如果Tu8並且n1000

(順便說一句,重復添加dx通常不是最好的方法,因為如果T是浮點類型,它會累積錯誤;最后一個元素不一定等於xend 。)

除非您將此作為學習練習,否則我建議您需要num_traits crate 的邊界,它具有Float之類的特征,在這里會派上用場:

use num_traits::Float;

pub fn linspace<T: Float + TryFrom<usize>>(x0: T, xend: T, n: usize) -> Vec<T> {
    let dx = (xend - x0) / (n - 1).try_into().unwrap_or_else(|_| panic!());
    let mut x = vec![x0; n];
    for i in 1..n {
        x[i] = x[i - 1] + dx;
    }
    x
}

但現在我得到了錯誤:'f64' 沒有實現特征'From'。

它未實現,因為存在無法精確表示為f64usize值。 錯誤是讓你決定如何處理這些。 如果遇到這樣的值,我的代碼會出現恐慌。

另外,我相信浮點加法會累積錯誤,因此基於乘法的計算可能是一個更好的主意:

pub fn linspace<T: Float + TryFrom<usize>>(x0: T, xend: T, n: usize) -> Vec<T> {
    let to_float = |i: usize| i.try_into().unwrap_or_else(|_| panic!());
    let dx = (xend - x0) / to_float(n - 1);
    (0..n).map(|i| x0 + to_float(i) * dx).collect()
}

操場

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM