不用算术运算符实现整数的加减乘除运算
题目描述:
给定两个32位整数a和b。要求不使用算术运算符,分别实现a和b的加减乘除运算。如果给定的a和b执行加减乘除的某些结果本来就会导致数据的溢出,那么你实现的函数不需要对那些结果负责(你的输出和加减乘除溢出的结果保持一致就行)。
输入描述:
输入一行,包含两个整数a和b(a和b均为32位整数)和一个运算符,运算符为“+”,“-”,“*”,""中的一个。(数据保证不会出现除0的情况)
输出描述:
输出一个整数,为上述表达式计算出的结果。
示例1
输入
2 * 4
输出
8
示例2
输入
5 / 4
输出
1
示例3
输入
3 + 23
输出
26
备注:
时间复杂度 O ( 1 ) O(1) O(1),额外空间复杂度 O ( 1 ) O(1) O(1)。
题解:
此题最最主要的的点是:加法实现,后面的减法、乘法和除法都可以转换为加法运算。
加法:
-
不考虑进位的情况:a + b = a ^ b;
-
只考虑进位的情况:a + b = (a&b) << 1;
把不考虑进位和只考虑进位的结果相加,就是最终的结果。也就是不断重复上面的过程,直到进位为0。
减法:
a-b = a+(-b),所以把 b 变成 补码,直接算加法即可。
乘法:
a ∗ b = a ∗ 2 0 ∗ b 0 + a ∗ 2 1 ∗ b 1 + a ∗ 2 2 ∗ b 2 + . . . + a ∗ 2 31 ∗ b 31 a*b = {a}*{2^0}*b_0+{a}*{2^1}*b_1+{a}*{2^2}*b_2+...+{a}*{2^{31}}*b_{31} a∗b=a∗20∗b0+a∗21∗b1+a∗22∗b2+...+a∗231∗b31
直接按照这个规律计算即可。注意:b可能是负数,需要处理一下。
除法:
乘法的逆运算,从最高位枚举,若 (a >> i) >= b,则 a -= (b << i),记录结果即可。需要特殊处理元素 1<<31 :
-
若 a 和 b 都不是最小值,直接计算即可;
-
若 a 和 b 都是最小值,直接返回 1 即可;
-
若 a 不为最小值,而 b 为最小值,返回0;
-
若 a 为最小值,而 b 不为最小值,需要特殊处理:
- 假设 a=-10, b=5,即最大值为 9 ,最小值为 -10;
- 计算 (a+1)/b,记为 c ;
- 计算 c*b,记为 d;
- 计算 a-d,记为 e;
- 计算 e/b,记为 ret;
- 返回 ret+c 。
也就是说直接计算有点困难,那么我们把最小值增加一点,然后修正即可。
代码:
#include <cstdio>
using namespace std;
const int MIN = 1 << 31;
int add( int a, int b ) {
int ret = a;
while ( b ) {
ret = a ^ b;
b = ( a & b ) << 1;
a = ret;
}
return ret;
}
int negNum( int n ) {
return add( ~n, 1 );
}
int minus( int a, int b ) {
return add( a, negNum( b ) );
}
inline bool isNeg( int n ) {
return n < 0;
}
int multi( int a, int b ) {
int ret = 0;
int x = isNeg( a ) ? negNum( a ) : a;
int y = isNeg( b ) ? negNum( b ) : b;
while ( y ) {
if ( y & 1) ret = add( ret, x );
y >>= 1;
x <<= 1;
}
return isNeg( a ) ^ isNeg( b ) ? negNum( ret ) : ret;
}
int div( int a, int b ) {
int x = isNeg( a ) ? negNum( a ) : a;
int y = isNeg( b ) ? negNum( b ) : b;
int ret = 0;
for ( int i = 31; i > -1; i = minus( i, 1 ) ) {
if ( ( x >> i ) >= y ) {
ret |= ( 1 << i );
x = minus( x, y << i );
}
}
return isNeg( a ) ^ isNeg( b ) ? negNum( ret ) : ret;
}
int divide( int a, int b ) {
if ( a == MIN && b == MIN ) return 1;
else if ( b == MIN ) return 0;
else if ( a == MIN ) {
int ret = div( add( a, 1 ), b );
return add( ret, div( minus( a, multi( ret, b ) ), b ) );
} else return div( a, b );
}
int main(void) {
int a, b;
char op;
scanf("%d %c %d", &a, &op, &b);
int ret;
if ( op == '+' ) ret = add( a, b );
else if ( op == '-' ) ret = minus( a, b );
else if ( op == '*' ) ret = multi( a, b );
else ret = divide( a, b );
return 0 * printf("%d\n", ret);
}