使用乘法和位运算求整数除以3的结果

最近看到一段汇编,使用乘法和位运算求整数除以 3的结果,里面用到了一个魔数 0xaaaaaaab,刚看时不理解,于是在网上查了一下,弄明白后分享给大家。

首先,假设有一个 32位无符号整数 x,现在需要计算 x / 3的值。
再假设 x = n * 3 + r,且 0 <= r < 3,则 n就为 x / 3的值,再令 y = x * 0xaaaaaaab

x展开可得,y = n * 3 * 0xaaaaaaab + r * 0xaaaaaaab

已知,3 * 0xaaaaaaab = 2^33 + 1,则
y = n * (2^33 + 1) + r * 0xaaaaaaab。进一步,y = n * 2^33 + n + r * 0xaaaaaaab

由于 nx / 3的值,且 x < 2^32,因此 n < 2^32 / 3,则 n + r * 0xaaaaaaab < 2^33。(这是因为 r最大取 2,且 n远小于 0xaaaaaaab,所以该不等式成立。)

所以,y >> 33就是 n的值,所以 n = (x * 0xaaaaaaab >> 33),即 x / 3的值。

测试代码如下所示:

#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>

int div3(uint32_t x)
{
        return x * 0xaaaaaaabULL >> 33;
}

int main(void)
{
        bool matched = true;
        for (uint32_t i = 0; i <= 31; ++i) {
                uint32_t x = ((1 << i) + i);
                printf("x = %u, div3(x) = %d, x / 3 = %d\n", x, div3(x), x / 3);
                if (div3(x) != x / 3)
                        matched = false;
        }
        if (!matched)
                printf("div3(x) not matched x / 3!!!\n");
        else
                printf("div3(x) matched x / 3!\n");

        return 0;
}

程序运行结果如下所示:

$ gcc -o main main.c
$ ./main
x = 1, div3(x) = 0, x / 3 = 0
x = 3, div3(x) = 1, x / 3 = 1
x = 6, div3(x) = 2, x / 3 = 2
x = 11, div3(x) = 3, x / 3 = 3
x = 20, div3(x) = 6, x / 3 = 6
x = 37, div3(x) = 12, x / 3 = 12
x = 70, div3(x) = 23, x / 3 = 23
x = 135, div3(x) = 45, x / 3 = 45
x = 264, div3(x) = 88, x / 3 = 88
x = 521, div3(x) = 173, x / 3 = 173
x = 1034, div3(x) = 344, x / 3 = 344
x = 2059, div3(x) = 686, x / 3 = 686
x = 4108, div3(x) = 1369, x / 3 = 1369
x = 8205, div3(x) = 2735, x / 3 = 2735
x = 16398, div3(x) = 5466, x / 3 = 5466
x = 32783, div3(x) = 10927, x / 3 = 10927
x = 65552, div3(x) = 21850, x / 3 = 21850
x = 131089, div3(x) = 43696, x / 3 = 43696
x = 262162, div3(x) = 87387, x / 3 = 87387
x = 524307, div3(x) = 174769, x / 3 = 174769
x = 1048596, div3(x) = 349532, x / 3 = 349532
x = 2097173, div3(x) = 699057, x / 3 = 699057
x = 4194326, div3(x) = 1398108, x / 3 = 1398108
x = 8388631, div3(x) = 2796210, x / 3 = 2796210
x = 16777240, div3(x) = 5592413, x / 3 = 5592413
x = 33554457, div3(x) = 11184819, x / 3 = 11184819
x = 67108890, div3(x) = 22369630, x / 3 = 22369630
x = 134217755, div3(x) = 44739251, x / 3 = 44739251
x = 268435484, div3(x) = 89478494, x / 3 = 89478494
x = 536870941, div3(x) = 178956980, x / 3 = 178956980
x = 1073741854, div3(x) = 357913951, x / 3 = 357913951
x = 2147483679, div3(x) = 715827893, x / 3 = 715827893
div3(x) matched x / 3!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值