#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