【问题标题】:How do I specify the rounding mode for floating point numbers?如何指定浮点数的舍入模式?
【发布时间】:2015-03-23 04:53:09
【问题描述】:

我想将浮点数四舍五入到最接近的整数,当“最接近的整数”出现平局时趋向正无穷大。

use std::num::Float;

fn main() {
    assert_eq!(-0.0, (-0.5).round()); // fails!
}

但是,round 的文档说:

距离 0.0 的中途情况舍入。

我还没有看到任何可以让我改变舍入模式的东西,但总有办法吧?

【问题讨论】:

  • IEEE 754 浮点标准中没有“最接近加无穷大”舍入模式。即使 Rust 允许您完全访问硬件的功能(它可能会或可能不会),它也不会提供这种舍入模式。您必须手动进行四舍五入。 blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1 中提供了三种不同的方法,而第二种方法至少应该易于修改,以便按照您想要的方式进行舍入。
  • @PascalCuoq 哎呀!这就是我假设的结果!以供将来参考,here's the list of the 5 rounding modes 实际存在。

标签: floating-point rust rounding


【解决方案1】:

看来Float::round的实现,至少对于f32f64,转发到roundf32/roundf64 instrinsics,它们本身是使用LLVM函数llvm.round.f32和@987654330实现的@。遗憾的是,documentation for llvm.round.* 没有说明如何控制舍入模式。 LLVM 参考中似乎也没有其他任何内容。我发现的其他函数甚至提到了舍入模式,要么指定了一个特定的舍入模式,要么说它是未定义的。

我找不到任何关于此的可靠信息。有 a post on the LLVM mailing list from 2011 谈论特定于 x86 的内在函数,还有一个 2013 post to the Native Client issue tracker 似乎在谈论 假设 内在以及如何难以移植。

盲目尝试:我会尝试编写一个小的 C 库来完成它并链接到它。 LLVM 似乎不直接支持它。

【讨论】:

    【解决方案2】:

    恐怕我不了解 Rust,但我写了以下 for Julia(基于 Arch Robinson 的类似序列从零开始的关系),您应该能够适应:

    y = floor(x)
    ifelse(x==y, y, copysign(floor(2*x-y),x))
    

    快速解释发生了什么:

    1. floor 查找小于或等于 x 的最接近的整数。
    2. 如果y==x,那么x 是一个整数,所以不需要四舍五入:请注意,这会捕获x 的绝对值大于253 的所有情况。
    3. floor(2*x-y) 将给出所需的答案:2*x 是准确的,我们不必担心由于第 2 步而溢出。除 -0.25 < x < 0 之外的所有情况的减法都是准确的,这将清楚地给出正确的答案无论如何。
    4. copysign 只是为了确保零具有正确的符号。如果你不被这些事情困扰,你可以把它关掉。

    步骤 2 和 3 可以用一个简单的分支代替:

    x-y < 0.5 ? y : y+1.0
    

    但如果我没记错的话,避免此处的分支使代码更加矢量化(这也是使用ifelse 而不是if 块的原因)。

    【讨论】:

    猜你喜欢
    • 2011-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多