如何在 Rust 中安全地将 float 转换为 int

Tim*_*mmm 15 rust

如何安全地将浮点类型(例如f64)转换为整数类型(例如u64)?换句话说,我想转换数字,但前提是它实际上可以由目标类型表示。

我发现了几个涵盖此内容且不重复的问题:

解决方案是使用as- 执行饱和转换。也u64::try_from(f64)没有实施。

最接近的似乎是f64::to_int_unchecked()但不幸的是它不安全。您可以轻松检查前两个安全要求(不是 NaN 或无穷大),但第三个有点乏味:Be representable in the return type Int, after truncating off its fractional part

我能想到的最好的办法就是使用将as其转换回f64并检查相等性,即

fn convert(x: f64) -> Option<u64> {
    let y = x as u64;
    if y as f64 == x {
        Some(y)
    } else {
        None
    }
}
Run Code Online (Sandbox Code Playgroud)

这是最好的选择吗?它在任何地方实施吗?

Loc*_*cke 0

一般来说,我会推迟 Clippy 使用的相关 lint 的最佳实践。Clippy 很好地概述了使用中可能存在的陷阱,x as y并提供了可能的解决方案。这些是我能找到的关于该主题的所有相关 lints:

但是,如果您想要的只是找到映射f64到的答案u64而不损失任何精度,则需要检查两个条件:

  • x是一个整数
  • x在目标类型的范围内
pub fn strict_f64_to_u64(x: f64) -> Option<u64> {
    // Check if fractional component is 0 and that it can map to an integer in the f64
    // Using fract() is equivalent to using `as u64 as f64` and checking it matches
    if x.fract() == 0.0 && x >= u64::MIN as f64 && x <= u64::MAX as f64 {
        return Some(x.trunc())
    }

    None
}
Run Code Online (Sandbox Code Playgroud)