如何更高效实现将浮点值四舍五入至最近2的幂的C++函数?
查找最近2的幂的性能优化方案
目前能找到的关于查找整数或浮点值下一个2的幂的方案很多,但查找最近2的幂的方案却很少。我自己实现了如下函数,它适用于所有非负且小于ULLONG_MAX的浮点值,但看起来不是最优实现。有没有性能更优的实现方式?
template <typename T> static constexpr T round_pow2(T v) { if constexpr (std::is_floating_point_v<T>) { auto high = static_cast<unsigned long>(std::ceil(v)); auto low = static_cast<unsigned long>(std::floor(v)); if (high == low) { return round_pow2<unsigned long>(high); } else { T a = static_cast<T>(round_pow2<unsigned long>(low)); T b = static_cast<T>(round_pow2<unsigned long>(high)); return std::abs(a - v) <= std::abs(b - v) ? a : b; } } else { T high = v - 1; for (T i = 1; i < static_cast<T>(sizeof(T)); i *= 2) { high |= high >> i; } high += 1; T low = high >> 1; return (high - v) < (v - low) ? high : low; } }
编辑补充
- @Eric:我的应用场景中,当
v==0时返回0是可接受的,但这在部分场景可能有问题,因为0并不是2的幂。 - @Blixodus:感谢你的解答,给我指明了方向。基于你的思路,我编写了如下函数:
template <typename T> constexpr T round_p2(T v) { if constexpr (std::is_floating_point_v<T>) { using R = std::conditional_t< std::is_same_v<T, double>, uint64_t, std::conditional_t<std::is_same_v<T, float>, uint32_t, void >>; auto [mlen, es, em] = std::is_same_v<T, double> ? std::make_tuple(52, 1024, 0x7FF) : std::make_tuple(23, 128, 0xFF); auto y = *reinterpret_cast<R*>(&v); return (T(y >> (sizeof(R) * 8 - 1)) * -2 + 1) * (2 << (((y >> mlen) & em) - es + ((y >> mlen - 1) & 0x1))); } else { using R = std::make_unsigned_t<T>; R rv = static_cast<R>(v); T sign = 1; if constexpr (std::is_signed_v<T>) { if (v < 0) { rv = static_cast<R>(-v); sign = -1; } } R high = rv - 1; for (R i = 1; i < static_cast<R>(sizeof(R)); i *= 2) { high |= high >> i; } high += 1; R low = high >> 1; return sign * static_cast<T>((high - rv) <= (rv - low) ? high : low); } }
这个函数在我的应用中表现良好,生成的汇编代码相比初始实现更简洁。
代码解析
- 首先根据
v是float还是double获取三个关键值:尾数长度、指数需减去的数值(加1)、用于提取浮点表示中指数的掩码。 - 将浮点值转换为同大小的无符号整数,以便进行位操作。
- 通过
(T(y >> (sizeof(R) * 8 - 1)) * -2 + 1)提取符号位,把0转为1,1转为-1,用于最终结果的符号标记。 - 最后利用位运算替代
std::pow计算最近的无符号2的幂,由于用移位操作替代幂函数,需要调整移位参数(因此es的值比预期大1)。
内容的提问来源于stack exchange,提问作者Sadiinso
相关产品推荐
相关产品推荐

