快速 log2 取整算法 (O(1) 时间与空间复杂度)
先上核心代码(文末附针对多种整数类型的代码):
inline int log_2(int x) { int rst = 0; if (x & 0xffff'0000U) rst += 16, x >>= 16; if (x & 0x0000'ff00U) rst += 8, x >>= 8; if (x & 0x0000'00f0U) rst += 4, x >>= 4; if (x & 0x0000'000cU) rst += 2, x >>= 2; if (x & 0x0000'0002U) rst += 1 ; return rst; }
原理很简单:
首先,任意正整数都可以拆分为数个互不相等的 2 的幂的和,且这些 2 的幂都小于等于该数;
其次,int
占用 32
位,故对于 int
范围内的数,其对数都不超过 31
;
最后,容易注意到二进制与对数间的天然联系,介于这种联系是显然且不易描述的,在此不予点明[doge];
综上,对于 int
类型的数据,其对数必然可以通过 {16, 8, 4, 2, 1}
组合出来,通过其二进制位即可判断其对数是由那几个数组合的。
附录(以下代码效率差别可以忽略不计,但代码量有显著差距):
inline auto log_2(uint64_t x) { // also unsigned long long uint64_t rst = 0; if (x & 0xffff'ffff'0000'0000ULL) rst += 32, x >>= 32; if (x & 0x0000'0000'ffff'0000ULL) rst += 16, x >>= 16; if (x & 0x0000'0000'0000'ff00ULL) rst += 8, x >>= 8; if (x & 0x0000'0000'0000'00f0ULL) rst += 4, x >>= 4; if (x & 0x0000'0000'0000'000cULL) rst += 2, x >>= 2; if (x & 0x0000'0000'0000'0002ULL) rst += 1 ; return rst; } inline auto log_2(uint32_t x) { // also unsigned int uint32_t rst = 0; if (x & 0xffff'0000U) rst += 16, x >>= 16; if (x & 0x0000'ff00U) rst += 8, x >>= 8; if (x & 0x0000'00f0U) rst += 4, x >>= 4; if (x & 0x0000'000cU) rst += 2, x >>= 2; if (x & 0x0000'0002U) rst += 1 ; return rst; } inline auto log_2(uint16_t x) { // also unsigned short uint16_t rst = 0; if (x & 0x0000'ff00U) rst += 8, x >>= 8; if (x & 0x0000'00f0U) rst += 4, x >>= 4; if (x & 0x0000'000cU) rst += 2, x >>= 2; if (x & 0x0000'0002U) rst += 1 ; return rst; } inline auto log_2(uint8_t x) { // also unsigned char uint8_t rst = 0; if (x & 0x00f0U) rst += 4, x >>= 4; if (x & 0x000cU) rst += 2, x >>= 2; if (x & 0x0002U) rst += 1 ; return rst; }
本文作者:Expector
本文链接:https://www.cnblogs.com/expector/p/fast-log_2.html
版权声明:本作品采用 CC BY-NC-ND 许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步