预备知识
这类题目我选择使用位运算,需要了解到:两个数异或(a^b
)结果是忽略进位的结果;两个数相与(a&b)<<1
结果是产生的进位结果
对于一个有符号数,其相反数等于它的补码按位取反再加1。以一个8位有符号数-7为例,其二进制表示为 10000111(其中最高位为符号位,0表示正数,1表示负数),将其转换为补码需要将其反码再加1,即:
反码: 1111 1000
补码: 1111 1001
因此,-7的补码为 11111001。
如果要求-7的相反数,则需要按位取反,即得到其反码为 0000 0110,补码为 0000 0111,其十进制表示为7。因此,-7的相反数为7。在计算机中,求一个数的相反数一般使用取反操作(~)和加法操作。具体操作如下:
int num = -7;
int oppositeNum = ~num + 1;
做加法
【测试链接】
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
示例: 输入: a = 1, b = 1
输出: 2
示例: 输入: a = 1, b = -2
输出: -1
在 C++的实现中,当我们赋给带符号类型一个超出它表示范围的值时,结果是 undefined;而当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模的余数。因此,我们可以使用无符号类型来防止溢出。
class Solution {
public:
int add(int a, int b) {
//只能正整数相加
// int carry=(a&b)<<1;
// int num=a^b;
// if(carry) num=add(num,carry);
// return num;
//整数和负数都可以
while (b)
{
size_t carry = (size_t)(a & b) << 1;
int num = a ^ b;
a = num;
b = carry;
}
return a;
}
};
做减法
-
减法运算可以直接用上面的加法。
-
自定义一个减法运算
~a 表示 a 的逐位取反操作,即 ~a = -a - 1。因此,carry 即为 a 和 b 的需要进位的位置。
最后,将 carry 左移一位作为进位,然后重复执行上述操作,直到 b 等于 0,即不再有进位为止。最终返回的结果即为不使用加减乘除实现的 a-b。
int subtract(int a, int b) {
int carry ;
while (b != 0) {
carry = (~a) & b; // 计算a和b的不进位相减结果
a ^= b; // 计算a和b的不考虑进位的加法结果
b = carry << 1; // b左移一位作为进位
}
return a;
}
- 或者是第一步对减数取反然后加1,第二步将第一步所得值和被减数相加
int subtract(int a, int b)
{
int subtrahend = add(~b, 1);//得到相反数
int sub = add(a, subtrahend);
return sub;
}
做乘法
乘法的本质就是加法
例如:1113—>10111101=10001111
首先判断乘数的第0位,这里第0位为1,因此第一个相加数为1101。然后判断乘数的第一位,这里第一位为0,所以第二个相加数为00000,即被乘数左移一位。继续看乘数的第二位,这里第二位为1,则第三个相加数为101100。最后看乘数的第四位,这里为1,所以最后一个相加数为1101000即被乘数左移三位。最后将获得的所有相加数都加起来,而这个和就是所要求的乘积(1101+11010+0+1101000=10001111)
根据二进制位可以想到,乘法中将被乘数乘以2同时乘数除以2,结果不变!!!
1011*1101==》1011*1 + 10110*0 + 101100*1 + 1011000*1
int multiply(int a, int b)
{
//将乘数和被乘数都取绝对值
int left = a < 0 ? add(~a, 1) : a;
int right = b < 0 ? add(~b, 1) : b;
//计算绝对值的乘积
int product = 0;
while (right)
{
if (right & 1)
{
product = add(left, product);
}
//被乘数左移一位
left = left << 1;
//乘数右移一位
right = right >> 1;
}
//计算乘积的符号
if ((a ^ b) < 0)
{
product = add(~product, 1);
}
return product;
}
做除法|取模
除法实现就是不停的用除数去减被除数,直到被除数小于除数时,此时所减的次数就是我们需要的商,而此时的被除数就是余数。需要注意的是商的符号和余数的符号。商的符号确定方式也乘法是一样,即同号为正,异号为负。而余数的符号和被除数的符号是一样的。和简单的乘法实现一样,这里我们要先对两数的绝对值求商,求余数。最后再确定符号。具体实现代码如下:
//求商
int divide(int a, int b)
{
//对被除数和除数取绝对值
int dividend = a < 0 ? add(~a, 1) : a;
int divisor = b < 0 ? add(~b, 1) : b;
//对被除数和除数的绝对值求商
int remainder = dividend;
int quotient = 0;//计数器(商)
while(remainder >= divisor)
{
remainder = subtract(remainder, divisor);//不断相减
quotient = add(quotient, 1);
}
//求商的符号
if((a ^ b) < 0)
{
quotient = add(~quotient, 1);
}
return quotient;
}
取模
//取模
int remainder(int a, int b)
{
//对被除数和除数取绝对值
int dividend = a < 0 ? add(~a, 1) : a;
int divisor = b < 0 ? add(~b, 1) : b;
int remainder = dividend;
while(remainder >= divisor)
{
remainder = subtract(remainder, divisor);
}
//取模的符号
if(a < 0)
{
remainder = add(~remainder, 1);
}
return remainder;
}
本文系个人见解,如有不妥,敬请指出