如前所述,没有内置方法。那么让我们看看有几种方法可以做到这一点。但首先...
性能注意事项:
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 float, 为 53 double, 为 64 long double。在我们的一点帮助下,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;
}
Run Code Online (Sandbox Code Playgroud)
通过改变我们的幻数p ,我们可以四舍五入到不同的 2 的幂。p - 1 将创建标准银行家四舍五入。
所有人都欢呼新的舍入方式:std::nearbyint。这遵循当前的舍入模式,因此如果舍入模式被其他东西弄乱了,我们可以使用std::fesetround它来将其恢复为FE_TONEAREST.
std::nearbyint( x * 0.5f ) * 2.0f
这与第一个版本一样直观,但没有任何偏见。