我正在尝试将两个软件结合在一起:一个给我 f32
,还有一个期望 f64
值。在我的代码中,我使用 f64::from(my_f32)
,但在我的测试中,我比较了结果,我比较的值没有按预期转换:f64
value 有一堆额外的、更精确的数字,因此值不相等。
在我的例子中,值为 0.23
.有没有办法转换 0.23_f32
至 f64
这样我最终得到 0.23_f64
而不是 0.23000000417232513
?
fn main() {
let x = 0.23_f32;
println!("{}", x);
println!("{}", f64::from(x));
println!("---");
let x = 0.23_f64;
println!("{}", x);
println!("{}", f64::from(x));
}
编辑:我知道 float 的存储方式不同——事实上,我使用 this handy visualizer有时查看 32 位和 64 位 float 之间的表示差异。我想看看是否有一些聪明的方法来解决这个问题。
编辑 2:我刚刚想到的一个“聪明”示例是 my_32.to_string().parse::<f64>()
--这让我明白了0.23_f64
,但(显然)需要字符串解析。我认为可能至少有一些与数字相关的东西(因为缺少更好的术语)。
最佳答案
评论已经指出了为什么会这样。这个答案的存在是为了给你提供规避这种情况的方法。
第一个(也是最明显的)是使用任意精度的库。使用rust 的一个很好的例子是 rug
.这允许您准确地表达几乎任何数字,但它会导致一些跨 FFI 边界的问题(在其他情况下)。
第二个是做大多数人围绕 float 所做的事情,并将等式括起来。因为您知道大多数 float 不会被准确存储,并且您知道您的输入类型,所以您可以使用诸如 std::f32::MIN
之类的常量。将您的类型括起来,像这样 ( playground ):
use std::cmp::PartialOrd;
use std::ops::{Add, Div, Sub};
fn bracketed_eq<
I,
E: From<I> + From<f32> + Clone + PartialOrd + Div<Output = E> + Sub<Output = E> + Add<Output = E>,
>(
input: E,
target: I,
value: I,
) -> bool {
let target: E = target.into();
let value: E = value.into();
let bracket_lhs: E = target.clone() - (value.clone() / (2.0).into());
let bracket_rhs: E = target.clone() + (value.clone() / (2.0).into());
bracket_lhs >= input && bracket_rhs <= input
}
#[test]
fn test() {
let u: f32 = 0.23_f32;
assert!(bracketed_eq(f64::from(u), 0.23, std::f32::MIN))
}
其中很大一部分是样板文件,其中很多都被编译器完全优化掉了;也可以删除 Clone
通过限制某些特征选择来满足要求。 Add
, Sub
, Div
有没有操作,From<I>
实现转换,From<f32>
对于常量 2.0
.
关于rust - 有没有办法从 `f64::from(0.23_f32)` 得到 0.23_f64?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58174531/