不用加号实现两整数相加

1.问题描述

不用加号实现两整数相加。

2.难度等级

middle。

3.热门指数

★★★☆☆

比较热门,需要掌握。

4.减法实现

负负得正,所以可以使用减号减去目标数的相反数来实现相加。

int addWithoutPlusSign(int a, int b) {
    return a - (-b);
}

5.异或实现

5.1 解题思路

对于二进制的加法运算,若不考虑进位,则 1+1=0,1+0=1,0+1=1,0+0=0,不难发现,结果等同于异或运算。因而排除进位,加法可用异或来实现。然后考虑进位,0+0 进位为 0,1+0 进位为 0,0+1 进位为 0,1+1 进位为1,结果等同于与运算。

设 a,b 为两个二进制数,a^b 是不考虑进位时加法结果。当二进制位同时为 1 时,才有进位,因此 (a&b)<<1 是进位产生的值,称为进位补偿。将两者相加便是完整的加法结果。

因此 a+b = a^b + (a&b)<<1。

那么加法运算可以这样实现:

(1)先不考虑进位,按位计算各位累加(用异或实现),得到值 a;

(2)然后再考虑进位,并将进位的值左移,得值 b。如果 b 不为 0 与 a 值继续相加。如果 b 为 0,则 a 就是加法运算的结果。此过程可循环或递归实现。

5.2 复杂度分析

时间复杂度:O(1),最差情况下(例如 a= 0x7fffffff,b = 1 时),需循环 32 次。

空间复杂度:O(1),使用常数大小的额外空间。

5.3 实现示例

5.3.1 C++

#include <iostream>
using namespace std;

// 循环实现。
// 以循环的方式通过位运算实现两整数相加。
int bitAdd (int a, int b) {
	int sum = a;
	while (b!=0) {
     	a  = sum;
		sum = a^b;
     	b =(a&b) << 1;
	}
	return sum;
}

// 递归实现。
// 以递归的方式通过位运算实现两整数相加。
int bitAdd (int a, int b) {
	if(b==0) {
		return a;
	}
	int sum = a^b;
	int carry =(a&b) << 1;
	return bitAdd(sum, carry);
}

int main() {
	cout << "9+1=" << bitAdd(9,1) << endl;
	cout << "99+11=" << bitAdd(99,11) << endl;
	cout << "-2+11=" << bitAdd(-2,11) << endl;
}

运行输出:

9+1=10
99+11=110
-2+11=9

6.内嵌汇编

以 GNU C++ 为例讲解。

C/C++ 函数返回值是通过寄存器 eax 返回,所以通过内联汇编指令的方式可以实现两数相加。注意 GNU C++ 内联汇编语法使用 AT&T/UNIX 语法,和 Visual C++ 的内联汇编语法不同。

#include <iostream>
using namespace std;

int asmAdd(int a,int b) {
    asm
    (
        "movl %0,%%eax\n\t"
        "movl %1,%%ecx\n\t"
        "addl %%ecx,%%eax"
        :
        :"r"(a),"r"(b)
    );
}

int main() {
	cout << "9+1=" << asmAdd(9,1) << endl;
    cout << "99+11=" << asmAdd(99,11) << endl;
    cout << "-2+11=" << asmAdd(-2,11) << endl;
}

使用g++ test.cpp编译运行结果如下:

9+1=10
99+11=110
-2+11=9

关于上述内联汇编代码的有如下几点解释:
(1)多行汇编指令使用 \n\t 进行换行,并使用双引号将单行指令括起来;
(2)使用双百分号引用寄存器,告诉编译器引用的是寄存器而非操作数;
(3)第一个冒号表示引用的 C++ 的变量,用于输出,因无需输出变量,所以留空;
(4)第二个冒号表示汇编代码需要读取的 C++ 的变量,"r"表示使用任意寄存器来存放变量 a 和 b 的值,多个变量使用逗号分隔。

在汇编代码中访问时,按照申请的顺序从数字 0 开始,使用 % 进行访问。比如上面代码中 %0 表示变量 a,%1 表示变量b。关于 GCC 的内联汇编语法,具体可以参见:GCC-Inline-Assembly-HOWTO


参考文献

不用加减乘除做加法 - Leetcode CN
不用算术运算符实现两个数的加法(按位异或).CSDN
GCC-Inline-Assembly-HOWTO

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值