在 C++ 中四舍五入到最近的偶数

Rounding to Nearest Even Number in C++

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

谢谢。

没有内置函数可以执行此操作。最直接的方法可能是做类似的事情:

even = round(x / 2) * 2;

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

性能注意事项:

  • 避免除法,因为它对浮点数来说仍然很慢,尽管不像对整数那样糟糕。对于浮点数,乘法几乎和加法一样快。
  • 乘以 2 -x 对于任何整数 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 是精度浮点数有效位数:float 为 24,double 为 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. This obeys the current rounding mode, so if the rounding mode's been twiddled with by something else, we can use std::fesetround 将其恢复为 FE_TONEAREST

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

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