【问题标题】:Rounding to Nearest Even Number in C++在 C++ 中舍入到最接近的偶数
【发布时间】:2015-07-16 20:42:15
【问题描述】:

我想知道 C++ 是否包含一种四舍五入到最接近偶数的方法。我环顾四周,似乎找不到有关该主题的任何内容。我可以编写自己的方法,但使用内置方法很可能会更快。

谢谢。

【问题讨论】:

  • 它是一个浮点值。

标签: int rounding


【解决方案1】:

没有内置函数可以做到这一点。最直接的方法可能是执行以下操作:

even = round(x / 2) * 2;

【讨论】:

  • 这正是我的做法。谢谢。
  • 但是在这种情况下你只能处理 0.5,当你第 1 轮时,你得到 2 但预期为 1。
  • @Yimu,问题是关于四舍五入到最接近的偶数。当你第 1 轮时,你会期望 2。
  • @Xavier,谢谢!可能还有另一个问题,将一半舍入但不影响其他舍入wiki: Round half to even
【解决方案2】:

如前所述,没有内置方法。因此,让我们看看可以做到这一点的几种方法。但首先...

性能注意事项:

  • 避免除法,因为它对于浮点数仍然很慢,尽管不如整数那么糟糕。乘法的速度几乎与浮点数的加法一样快。
  • 保证任何整数 x 乘以 2 -x 等价于 除以 2 x,同时不损失精度。
  • 将所有常量设置为同一类型以防止升级,尤其是当值将再次以同一类型存储时。

简单

std::round( x * 0.5f ) * 2.0f

这将在每个奇数处从零四舍五入,从而产生一个小的偏差。

一般情况下,尽可能避免使用std::round。它之所以慢,是因为它必须:保存舍入模式,切换它,舍入,然后恢复之前的舍入模式。所有这些都是为了引入偏见。

幻数

在 C++11 之前,我们可以使用内置的银行家四舍五入来使用幻数来缓解偏差。 警告:这依赖于默认的舍入模式 (FE_TONEAREST),它通常是 99.9999% 的时间,但要小心其他库可能会更改它而不是在之后恢复它。

float魔术:( x + 25165824f ) - 25165824f

这使用了浮点精度只有这么多位的事实。通过添加一个足够大的幻数,我们不想要的最低位将自动舍入,然后我们减去我们的幻数,使原始四舍五入到正确的精度。

幻数计算为 1.5 * 2 p 其中 p 是浮点有效数的精度:24 表示 floatdouble 为 53,long double 为 64。在std::numeric_limits 的一点帮助下,我们可以使这个通用化。

template< typename T >
T magic_round_to_even( T x ) {
  static T magic = 1.5 * std::pow( 2.0L, std::numeric_limits< T >::digits);
  return ( x + magic ) - magic;
}

通过将 p 更改为我们的幻数,我们可以四舍五入到 2 的不同幂次。 p - 1 将创建标准的银行家四舍五入。

C++11

大家欢迎新的回合方法:std::nearbyint。这符合当前的舍入模式,所以如果舍入模式被其他东西弄乱了,我们可以使用std::fesetround将其恢复为FE_TONEAREST

std::nearbyint( x * 0.5f ) * 2.0f

这与第一个版本一样直观,但没有任何偏见。

【讨论】:

  • 避免除法,因为浮点数仍然很慢 - 编译器可以优化 x / 2.0fx * 0.5f 到同一件事。 gcc.godbolt.org/z/YTm7zu
  • 如果你使用的是nearbyint,则不需要做乘法。如果你假设FE_TONEAREST,结果就是std:nearbyint(x)。 FE_TONEAREAT 是四舍五入。
  • @AllanJensen,FE_TONEAREST 是四舍五入到最接近的平数,而不是四舍五入到偶数。所以你确实需要乘法。
猜你喜欢
  • 1970-01-01
  • 2019-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 2014-04-21
相关资源
最近更新 更多