2018-01-15 A+B 不用加号实现整数相加
2018-01-15 本文已影响241人
BlackChen
直接上代码
#include <stdio.h>
int add_one(int a, int b) {
return a - (-b);
}
int add_two(int a, int b) {
char *p = (char *) a;
int c = (int) &p[b];
return c;
}
int add_three(int a, int b) {
if (0 == b)
return a;
int cxor = a ^b;
int cand = a & b;
return add_three(cxor, cand << 1);
}
int add_four(int a, int b) {
int cxor = 0;
int cand = 0;
while (b != 0) {
cxor = a ^ b;
cand = (a & b) << 1;
a = cxor;
b = cand;
}
return cxor;
}
int main() {
printf("#########ONE#########\n");
int c = add_one(-20, -20);
printf("c = %d\n", c);
printf("#########TWO#########\n");
c = add_two(-30, -20);
printf("c = %d\n", c);
printf("#########THREE#########\n");
c = add_three(-40, 90);
printf("c = %d\n", c);
printf("#########FOUR#########\n");
c = add_four(40, -50);
printf("c = %d\n", c);
return 0;
}
输出:
#########ONE#########
c = -40
#########TWO#########
c = -50
#########THREE#########
c = 50
#########FOUR#########
c = -10
add_one
int add_one(int a, int b) {
return a - (-b);
}
不解释.......小聪明
add_two
int add_two(int a, int b) {
char *p = (char *) a;
int c = (int) &p[b];
return c;
}
使用p[b]
获取char
数组 b个字节的偏移量.
int main() {
char a[10] = {'1','2','3','4','5'};
char *p = a;
printf("p = %p\n",p);
printf("a = %p\n",&a);
printf("a[2] = %c\n",a[2]);
printf("p+2= %c\n",*(p+2));
printf("a[2]的地址: ,%p\n",&a[2]);
printf("p + 2 的地址: %p\n",p+2);
}
输出:
p = 0x7fff5ade795e
a = 0x7fff5ade795e
a[2] = 3
p+2= 3
a[2]的地址: ,0x7fff5ade7960
p + 2 的地址: 0x7fff5ade7960
指针 + 数字--> 指针类型指向的类型长度 * 数字 + 指针本来地址,现在把char 换为int
int a[10] = {'1', '2', '3', '4', '5'};
int *p = a;
printf("p = %p\n", p);
printf("a = %p\n", &a);
printf("a[2] = %d\n", a[2]);
printf("p+2= %d\n", *(p + 2));
printf("a[2]的地址: ,%p\n", &a[2]);
printf("p + 2 的地址: %p\n", p + 2);
输出:
p = 0x7fff57360940
a = 0x7fff57360940
a[2] = 51
p+2= 51
a[2]的地址: ,0x7fff57360948
p + 2 的地址: 0x7fff57360948
add_three 和 add_four
int add_three(int a, int b) {
if (0 == b)
return a;
int cxor = a ^b;
int cand = a & b;
return add_three(cxor, cand << 1);
}
使用位运算来计算加法,涉及到位的操作.
-
^
异火运算符 简称不进位加法
0 ^ 0 = 0
1 ^ 0 = 1
1 ^ 1 = 0 -
&
与运算符
0 ^ 0 = 0
1 ^ 0 = 0
1 ^ 1 = 1
使用^
运算符可以计算出两个数相加的所有不进位的值
使用&
运算符可以计算出两个数相加的所有进位值,
例如 :
- 计算 a = 11
b = 5
a + b = 16
a = 11 的二进制表示 1011
b = 5 的二进制表示 0101
cxor = a ^ b = 1 0 1 1
0 1 0 1
1 1 1 0
cand = a & b = 1 0 1 1
0 1 0 1
0 0 0 1
然后 cand << 1 = 0010,有进位,再次做运算
cxor = 1110 ^ 0010 = 1100
cand = 1110 & 0010 = 0010
cand << 1 = 0100, 有进位,再次做运算
cxor = 1100 ^ 0100 = 1000
cand = 1100 & 0100 = 0100
cand << 1 = 1000, 有进位,再次做运算
cxor = 1000 ^ 1000 = 0000
cand = 1000 ^ 1000 = 1000
cand << 1 = 0001 0000 有进位,再次做运算
cxor = 0000 0000 ^ 0001 0000 = 0001 0000
cand = 0000 0000 & 0001 0000 = 0000 0000
cand << 1 = 0 无进位,运算结束,相加值为 0001 000 = 16
我们计算一下负数的相加:
这里我们要清楚的是,所有的数值在计算机中存储的都是补码
将一个整数,转换成二进制,就是其原码。如单字节的5的原码为:0000 0101;-5的原码为1000 0101。
反码:正数的反码就是其原码;负数的反码是将原码中,除符号位以外,每一位取反。如单字节的5的反码为:0000 0101;-5的反码为1111 1010。
补码:正数的补码就是其原码;负数的反码+1就是补码。如单字节的5的补码为:0000 0101;-5的原码为1111 1011。
在计算机中,正数是直接用原码表示的(正数的源码= 反码 = 补码),如单字节5,在计算机中就表示为:0000 0101。负数用补码表示,如单字节-5,在计算机中表示为1111 1011。
- 计算 a = - 11
b = 5
a + b = - 6
a = -11 在计算机中的二进制补码表示 1111 0101
b = 5 的二进制表示 0000 0101
cxor = a ^ b = 1111 0101
0000 0101
1111 0000
cand = a & b = 1111 0101
0000 0101
0000 0101
然后 cand << 1 = 0000 1010 ,有进位,再次做运算
cxor = 1111 0000 ^ 0000 1010= 1111 1010
cand = 1111 0000 & 0000 1010 = 0000 0000
cand << 1 = 0 无进位,运算结束,相加值为 1111 1010 最高位为 1 说明是负数,现在把补码转换为源码:
先减1 ,然后除符号位外按位取反:
减 1 :
1111 1010 - 0000 0001 = 1111 1001
取反:
1111 1001 ---> 1000 0110
0110 = 6
最高位为 1 所以为 -6
总结
- 使用到了计算机中数值的表示,源码,反码,补码 ,计算机中是用补码来表示数值的
- 使用到地址的运算,与指针的运算
- 使用到
^
异或操作符 与&
与 操作符.