位操作_利用二进制的位操作实现整数加减乘除的代码实现

#include <iostream>
using namespace std;

//二进制实现加法
int add(int num1, int num2)
{
    int sum = num1 ^ num2;//等于不进位相加

    int carry = (num1 & num2) << 1; //等于只进位

    while (carry != 0)
    {
        int a = sum;
        int b = carry;

        sum = a ^ b;

        carry = (a & b) << 1;

    }
   
    return sum;
}

//二进制实现减法,减去一个数等于加上一个负数。
//取反加一可以变号,计算机采用补码运算,负数的补码是符号位不变其他取反加一。
int substract(int num1,int num2)
{
    int sub = add(~num2, 1);//取反加一

    return add(num1, sub);
}

//乘法可以转换为加法,需要注意判断符号。
//先求绝对值,再判断符号。
//这种方法是低效率版,num1为被乘数,num2为乘数
int  multiply(int num1, int num2)
{
    int a = num1 > 0 ? num1 : add(~num1, 1);
    int b = num2 > 0 ? num2 : add(~num2, 1);
    
    int count = 0;
    int sum = 0;

    while (count < b)
    {
        sum = add(a , sum);
        count = add(count, 1);
    }
    
    if ((num1 ^ num2) < 0)
        return add(~sum, 1);
    else
        return sum;
}


//高效率版本
//利用手算式规律
int  multiply2(int num1, int num2)
{
    int a = num1 > 0 ? num1 : add(~num1, 1);
    int b = num2 > 0 ? num2 : add(~num2, 1);

    int product = 0;

    while (b != 0)
    {
        //(b & 0x1)是为了获得乘数的二进制的最后一位数,如果是0则不操作,不是0则和上次算式的结果相加
        if ((b & 0x1) != 0)
        {
            product = add(product , a);
        }
        a = a << 1;
        b = b >> 1;
        
    }
    
    if ((num1 ^ num2) < 0)
        return add(~product, 1);

    else
        return product;
}

//除法可以转换为减法,需要注意判断符号。
//先求绝对值,再判断符号。
//这种方法是低效率版,num1为被除数,num2为除数

int divide(int num1, int num2)
{
    if (num2 == 0)
    {
        cout << "Divisor must not be equal to 0" << endl;
        return -1;
    }
    

    int a = num1 > 0 ? num1 : add(~num1, 1); //a为num1绝对值
    int b = num2 > 0 ? num2 : add(~num2, 1);//b为num2绝对值

    int quo = 0;//商
    int rem = 0;//余数

    while (b < a)
    {
        a = substract(a, b);
        quo = add(quo, 1);
    }
    // 确定余数符号    
    rem = b > 0 ? a : add(~a, 1);

    // 确定商的符号    
    if ((num1 ^ num2) < 0) // 如果除数和被除数异号,则商为负数  
        return add(~quo, 1);

    else return quo;// 返回商

}
//高效版
//上个版本在被除数很大,除数很小的时候要重复很多次,原因在于步长太小
//这个方法用2^i次方倍来快速逼近,提高效率
//x >> i 等于 x * (1/2)^i, x << i 等于x * 2^i
int divide2(int num1, int num2)
{
    if (num2 == 0)
    {
        cout << "Divisor must not be equal to 0" << endl;
        return -1;
    }
    

    int a = num1 > 0 ? num1 : add(~num1, 1); //a为num1绝对值
    int b = num2 > 0 ? num2 : add(~num2, 1);//b为num2绝对值

    int quo = 0;//商
    int rem = 0;//余数

    for (int i = 31; i >= 0; i--) //整数最大值为2^31
    {
        //比较a是否大于b的(1<<i)次方,不要将a与(b<<i)比较,而是用(a>>i)与b比较,
        //效果一样,但是可以避免因(b<<i)操作可能导致的溢出,如果溢出则会可能a本身小于b,但是溢出导致a大于b      
        if ((a >> i) >= b) {
            quo = add(quo, 1 << i);// (1 << i)相当于加上了2^i
            a = substract(a, b << i);// 再从被除数中减去b*2^i
        }
    }
    // 确定余数符号    
    rem = b > 0 ? a : add(~a, 1);

    // 确定商的符号    
    if ((num1 ^ num2) < 0) // 如果除数和被除数异号,则商为负数  
        return add(~quo, 1);

    else return quo;// 返回商

}

//测试函数
void test(int t1, int t2)
{
    
    int res1 = add(t1, t2);
    if(res1 == t1 + t2)
        printf("addPassed.\n");
    else
        printf("addFAILED.\n");

    int res2 = substract(t1, t2);
    if (res2 == t1 - t2)
        printf("substractPassed.\n");
    else
        printf("substractFAILED.\n");

    int res3 = multiply(t1, t2);
    if (res3 == t1 * t2)
        printf("multiplyPassed.\n");
    else
        printf("multiplyFAILED.\n");

    int res4 = multiply2(t1, t2);
    if (res4 == t1 * t2)
        printf("multiply2Passed.\n");
    else
        printf("multiply2FAILED.\n");

    int res5 = divide(t1, t2);
    if (res5 == t1 / t2)
        printf("dividePassed.\n");
    else
        printf("divideFAILED.\n");

    int res6 = divide2(t1, t2);
    if (res6 == t1 / t2)
        printf("divide2Passed.\n");
    else
        printf("divide2FAILED.\n");
        
}

void test1()
{
    test(1,3);
   
}
void test2()
{
    test(-1, 3);
}
void test3()
{
    test(1, -3);
}
void test4()
{
    test(-1, -3);
}
void test5()
{
    test(0, 3);
}
void test6()
{
    test(1, 0);
}

int main()
{
    test1();
    test2();
    test3();
    test4();
    test5();
    //test6();
    

}

运行结果:
在这里插入图片描述
参考资料1:https://blog.csdn.net/YPJMFC/article/details/78246971
参考资料2:https://blog.csdn.net/u014082714/article/details/43193173

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值