有没有办法去`f64 :: from(0.23_f32)`并获得0.23_f64?

问题描述 投票:1回答:2

我正在尝试将两个软件捆绑在一起:一个给我一个f32,另一个期望f64值。在我的代码中,我使用f64::from(my_f32),但是在我的测试中,我比较了结果,并且比较的值未按预期进行转换:f64值有一堆额外的,更精确的数字,因此值不相等。

在我的情况下,值为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));
}

Playground


编辑:我了解浮点数的存储方式不同-实际上,我偶尔使用this handy visualizer来查看32位浮点数和64位浮点数之间的表示形式差异。我一直在寻找是否有解决这个问题的聪明方法。


编辑2:我刚刚想到的一个“聪明”示例将是my_32.to_string().parse::<f64>() -使我得到0.23_f64,但(显然)需要字符串解析。我想认为可能至少有些数字相关(因为缺少更好的用语)。

rust floating-point
2个回答
1
投票

评论已经指出了为什么会这样。存在此答案可为您提供规避此问题的方法。

第一个(也是最明显的)是使用任意精度的库。锈的一个可靠例子是rug。这使您可以精确地表达几乎任何数字,但会在FFI边界上引起一些问题(在其他情况下)。

第二是围绕浮点数做大多数人要做的事情,并用括号括起来。由于您知道大多数浮点数将不会被完全存储,并且您知道输入类型,因此可以使用诸如rug的常量括起来,例如(std::f32::MIN):

std::f32::MIN

大量的样板文件,很多被编译器完全优化;也可以通过限制某些性状选择来降低playground要求。 use std::ops::{Add, Sub, Div}; use std::cmp::PartialOrd; 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)) } CloneAdd用于操作,Sub用于实现转换,Div用于常数From<I>


0
投票

比较浮点值的正确方法是将它们括起来。问题是如何确定包围间隔?在您的情况下,由于您将目标值表示为From<f32>,因此有两种解决方案:

  • 显而易见的解决方案是在2.0之间进行比较,因此将f32结果转换为f32以去除多余的数字,并将其与预期结果进行比较。当然,如果累积的舍入误差导致结果略有不同,这可能仍然会失败。

  • 正确的解决方法是使用f64函数来获取目标周围的最小包围间隔:

    f32

    但不幸的是,这从未稳定下来(请参阅next_after)。

  • 因此,您必须确定可接受的精度,可能取决于next_after

    let result: f64 = 0.23f64;
    let expect: f32 = 0.23;
    
    assert_ne!(result, expect.into());
    assert!(expect.next_after (0.0).into() < result && result < expect.next_after (1.0).into());
    
© www.soinside.com 2019 - 2024. All rights reserved.