From 和 Into 特性以及 usize 到 f64 的转换 [英] From and Into traits and conversion of usize to f64

查看:36
本文介绍了From 和 Into 特性以及 usize 到 f64 的转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试以非常通用的方式编写一些 Rust 代码,而没有明确指定类型.但是,我到了需要将 usize 转换为 f64 的地步,但这是行不通的.据推测,f64 没有足够的精度来保存任意的 usize 值.在夜间频道上编译时,我收到一条错误消息:error: the trait `core::convert::From<usize>` is not implementation for type `f64` [E0277].>

如果我想编写尽可能通用的代码,有什么替代方法?显然,我应该使用一个可能失败的转换特性(与 IntoFrom 不同).已经有这样的事情了吗?是否有通过 as 实现转换的特征?

这是下面的代码.

#![feature(zero_one)]使用 std::num::{零,一};使用 std::ops::{Add, Mul, Div, Neg};使用 std::convert::{From, Into};///计算多项式或截断的倒数///系列.//////如果输入的长度为 `n`,则执行 `n^2`///乘法.因此,当类型为n^2"时,复杂度为///的条目是有界的,但如果类型是,它可以更大///无界,至于 BigInt.///fn series_reciprocal T(a:&Vec T) ->Vec T其中T:零+一+加<输出=T>+Mul<输出=T>+Div<输出=T>+负<输出=T>+ 复制 {让 mut res:Vec T= vec![T::zero();a.len()];res[0] = T::one()/a[0];因为我在 1..a.len() {res[i] = a.iter().跳过(1).zip(res.iter()).map(|(&a, &b)| a * b).fold(T::zero(), |a, b| a + b)/(-a[0]);}资源}///这计算了一系列 `n` 值的比率 `B_n/n!`///其中`B_n` 是伯努利数.我们使用公式//////z/(e^z - 1) = \sum_{k=1}^\infty \frac {B_k}{k!} z^k.//////为了找到比率,我们截断了系列//////(e^z-1)/z = 1 + 1/(2!) z + 1/(3!) z^2 + ...//////到所需的长度,然后计算逆.///fn bernoulli_over_factorial<T,U>(n:U)->Vec T在哪里U:进入<使用>+ 复制,T:零+一+加<输出=T>+Mul<输出=T>+添加<输出=T>+ Div<输出=T>+负<输出=T>+复制 + 从<使用大小>{让 mut ans: Vec;= vec![T::zero();n.into()];ans[0] = T::one();对于 1..n.into() { 中的 kans[k] = ans[k - 1]/(k + 1).into();}series_reciprocal(&ans)}fn 主(){让 v = vec![1.0f32, 1.0f32];让 inv = series_reciprocal(&v);println!("v = {:?}", v);println!("v^-1 = {:?}", inv);让 bf = bernoulli_over_factorial::(30i8);}

解决方案

问题是整数→浮点数转换,其中浮点类型与整数大小相同或小于整数,不能保留所有值.所以 usizef64 在 64 位上失去精度.

这些类型的转换基本上是 conv crate,它定义了类型之间的许多易出错的转换(主要是内置的数字类型).这(截至 10 分钟前)包括 isize/usizef32/f64.

使用conv,你可以这样做:

使用 conv::prelude::*;...其中 T:ValueFrom+ ......ans[k] = ans[k - 1]/(k + 1).value_as::<T>().unwrap();...

免责声明:我是相关板条箱的作者.

I've been trying to write some Rust code in a very generic way, without specifying the types explicitly. However, I arrived at a point where I need to convert a usize to a f64 and this doesn't work. Presumably, f64 does not have enough precision to hold a an arbitrary usize value. When compiling on the nightly channel I get an error message: error: the trait `core::convert::From<usize>` is not implemented for the type `f64` [E0277].

What is the alternative, then, if I want to write the code as generic as possible? Clearly I should use a trait for conversion which can fail (unlike Into or From). Is there something like that already? Is there a trait for implementing the conversion by as?

Here is the code below.

#![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);
}

解决方案

The problem is that integer → floating point conversions, where the float type is the same size or smaller than the integer, cannot preserve all values. So usizef64 loses precision on 64-bit.

These sorts of conversions are basically the raison d'être for the conv crate, which defines numerous fallible conversions between types (mostly built-in numeric ones). This (as of 10 minutes ago) includes isize/usizef32/f64.

Using conv, you can do this:

use conv::prelude::*;

...

where T: ValueFrom<usize> + ...

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

Disclaimer: I am the author of the crate in question.

这篇关于From 和 Into 特性以及 usize 到 f64 的转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆