关于rust:From和Into特性以及usize到f64的转换

From and Into traits and conversion of usize to f64

我一直试图以一种非常通用的方式编写一些Rust代码,而没有明确指定类型。 但是,我到达需要将usize转换为f64的地步,这不起作用。 可能f64的精度不足以容纳任意usize值。 在夜间频道上编译时,出现错误消息:error: the trait `core::convert::From` is not implemented for the type `f64` [E0277]

那么,如果我想编写尽可能通用的代码,那有什么选择呢? 显然,我应该使用可能会失败的特征(与IntoFrom不同)。 已经有那样的东西了吗? 通过as进行转换是否具有特征?

这是下面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#![feature(zero_one)]
use std::num::{Zero, One};
use std::ops::{Add, Mul, Div, Neg};
use std::convert::{From, Into};

/// Computes the reciprocal of a polynomial or of a truncation of a
/// series.
///
/// If the input is of length `n`, then this performs `n^2`
/// multiplications.  Therefore the complexity is `n^2` when the type
/// of the entries is bounded, but it can be larger if the type is
/// unbounded, as for BigInt's.
///
fn series_reciprocal< T >(a: &Vec< T >) -> Vec< T >
    where T: Zero + One + Add<Output=T> + Mul<Output=T> +
             Div<Output=T> + Neg<Output=T> + Copy {

    let mut res: Vec< T > = vec![T::zero(); a.len()];
    res[0] = T::one() / a[0];

    for i in 1..a.len() {
        res[i] = a.iter()
                  .skip(1)
                  .zip(res.iter())
                  .map(|(&a, &b)| a * b)
                  .fold(T::zero(), |a, b| a + b) / (-a[0]);
    }
    res
}

/// This computes the ratios `B_n/n!` for a range of values of `n`
/// where `B_n` are the Bernoulli numbers.  We use the formula
///
///    z/(e^z - 1) = \\sum_{k=1}^\\infty \\frac {B_k}{k!} z^k.
///
/// To find the ratios we truncate the series
///
///    (e^z-1)/z = 1 + 1/(2!) z + 1/(3!) z^2 + ...
///
/// to the desired length and then compute the inverse.
///
fn bernoulli_over_factorial<T, U>(n: U) -> Vec< T >
    where
        U: Into<usize> + Copy,
        T: Zero + One + Add<Output=T> + Mul<Output=T> +
           Add<Output=T> + Div<Output=T> + Neg<Output=T> +
           Copy + From<usize> {
    let mut ans: Vec< T > = vec![T::zero(); n.into()];
    ans[0] = T::one();
    for k in 1..n.into() {
        ans[k] = ans[k - 1] / (k + 1).into();
    }
    series_reciprocal(&ans)
}

fn main() {
    let v = vec![1.0f32, 1.0f32];
    let inv = series_reciprocal(&v);
    println!("v = {:?}", v);
    println!("v^-1 = {:?}", inv);
    let bf = bernoulli_over_factorial::<f64,i8>(30i8);
}


问题是整数→浮点转换(浮点类型的大小等于或小于整数)不能保留所有值。 因此usizef64在64位上失去精度。

这些类型的转换基本上是conv条板箱的存在理由,它定义了类型(主要是内置数字类型)之间的许多易犯错误的转换。 (截至10分钟前)包括isize / usizef32 / f64

使用conv,您可以执行以下操作:

1
2
3
4
5
6
7
8
9
use conv::prelude::*;

...

where T: ValueFrom<usize> + ...

...
ans[k] = ans[k - 1] / (k + 1).value_as::< T >().unwrap();
...

免责声明:我是有关箱子的作者。


您可以使用as来做到这一点:

1
let num: f64 = 12 as f64 ;