使用位运算实现加减乘除

加法#

在二进制下,有异或操作、与操作、进位操作。异或操作是指两个数对应位置相同取0,不同取1;与操作是同为1取1,否则取0;进位就是各位置上的1或0左移若干位。
根据这些操作特性,加法可以分解成这样的过程,先是两个数异或,相当于得到了两个数没有进位的相加结果,然后两个数相与,相当于只有两个位置都是1的情况下该位置才能为1,再进一位,就等效了加法的进位操作,然后将这个无进位的相加结果与进位的结果进行相加,就等于一个完成的加法过程了。需要注意的是,无进位的相加结果和进位的结果的加法过程又可以分解,于是得到了一个递归过程。

int a = 13;
int b = 42;
while(b != 0) {
    int temp = a ^ b;
    b = (a & b) << 1;
    a = temp;
}
cout << a;

减法#

学习四则运算的时候我们就知道,减去一个数等于加上这个数的相反数,二进制中相反数可以这样表示-x = ~x + 1,也就是取反加1。

int a = 13;
int b = 42;
int c = ~b;
b = 1;
while(b != 0) {
    int tmp = c ^ b;
    b = (c & b) << 1;
    c = tmp;
}
while(c != 0) {
    int tmp = a ^ c;
    c = (a & c) << 1;
    a = tmp;
}
cout << a;

乘法#

乘法运算就像是列一个二进制的乘法竖式一样。假设x是乘数,y是被乘数,那么如果x的当前位是1,就把y直接加到结果中,否则就下一轮操作。

int a = 13;
int b = 42;
int res = 0;
while(b != 0) {
    if((b & 1) != 0) {
        int tmp_a = a;
        // 执行加法
        while( tmp != 0) {
            int tmp = tmp_a ^ res;
            tmp_a = (res & tmp_a) << 1;
            res = tmp;
        }
    }
    a <<= 1;
    b >>= 1;
}
cout << res;

除法#

除法就是乘法的逆运算。

int a = 42, b = 4;
int quotient = 0;     //商
int remain = a;       //余数
for(int i = 31; i > -1; i--) {    //除数左移等于被除数右移,还能避免溢出
    if((remain >> i) >= b) {
        int temp = 1 << i;    //1在商中的各位
        int temp2;
        while(temp != 0) {    //求商
            temp2 = quotient ^ temp;
            temp = (quotient & temp) << 1;
            quotient = temp2;
        }
        temp = ~(b << i);      //b左移i位后的相反数
        temp2 = 1;
        int temp3;
        while(temp2 != 0) {
            temp3 = temp ^ temp2;
            temp2 = (temp & temp2) << 1;
            temp = temp3;
        }
        while(temp != 0) {    //求余
            temp2 = remain ^ temp;
            temp = (remain & temp) << 1;
            remain = temp2;
        }
    }
}
//没有考虑负数情况,若引入负数需要标记结果的正负
cout << "位运算结果: " << quotient << endl;

作者:cwtxx

出处:https://www.cnblogs.com/cwtxx/p/18718214

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   cwtxx  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示