如何指定浮点数的舍入方式?

How do I specify the rounding mode for floating point numbers?

我想将浮点数舍入到最接近的整数,当 "nearest integer" 并列时趋于正无穷大。

use std::num::Float;

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

然而,round 的文档说:

Round half-way cases away from 0.0.

我还没有看到任何可以让我改变舍入模式的东西,但总有一些方法,对吗?

看起来 Float::round 的实现,至少对于 f32f64,转发到 roundf32/roundf64 内部函数,它们本身使用 LLVM 函数 llvm.round.f32llvm.round.f64 实现。遗憾的是,documentation for llvm.round.* 没有说明如何控制舍入模式。 LLVM 参考资料中似乎也没有关于它的任何其他内容。我发现的其他函数甚至提到了舍入模式或者指定了 one 特定的舍入模式,或者说它是未定义的。

我找不到关于此的任何可靠信息。有 a post on the LLVM mailing list from 2011 that talks about x86-specific intrinsics, and a 2013 post to the Native Client issue tracker 似乎在谈论 假设的 内在特性以及如何难以移植。

盲目尝试:我会尝试编写一个小的 C 库来完成它,然后 link 就可以了。 LLVM 似乎不直接支持它。

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

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

对正在发生的事情的快速解释:

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

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

x-y < 0.5 ? y : y+1.0

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