美文网首页算法程序员
2018-01-15 A+B 不用加号实现整数相加

2018-01-15 A+B 不用加号实现整数相加

作者: BlackChen | 来源:发表于2018-01-15 11:24 被阅读241次

直接上代码

#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 

总结

  1. 使用到了计算机中数值的表示,源码,反码,补码 ,计算机中是用补码来表示数值的
  2. 使用到地址的运算,与指针的运算
  3. 使用到^异或操作符 与 & 与 操作符.

相关文章

  • 2018-01-15 A+B 不用加号实现整数相加

    直接上代码 add_one 不解释.......小聪明 add_two 使用p[b] 获取char数组 b个字节的...

  • 【leetcode】 两整数之和, 不用+-号,如何实现两数相加

    【leetcode】 两整数之和, 不用+-号,如何实现两数相加 题目: 不使用运算符 + 和 - ,计算两整数 ...

  • A+B问题

    不用加号计算A+B,我们用异或运算和与运算以及位运算来实现同等的操作,A^B的二进制异或运算,相当于没有进位的加号...

  • 可变参数函数

    可变参数实现:多个整数相加

  • Python 基础知识全篇-数字(Numbers)

    整数 整数的基本操作如你预想的那样,相对直观简洁。相加和相减就用加号和减号,乘法用星号,除法用斜杠,幂乘用双星号 ...

  • 不用加号实现加法

    题目说明 这是一道在lintcode上的简单题:http://lintcode.com/en/problem/a-...

  • [leecode题目]超大整数相加Python实现

    超过一定长度的整数相加会溢出,那怎么实现超大整数数相加呢? 可能有人说,直接相加不行么,可能真不行,超过了类型长度...

  • css中神奇的负数

    outline-offset(负值)实现加号 能否用纯css实现加号,在不用伪类的情况下。 注意事项: 容器得是个...

  • 不用加法实现a+b

    这到算法题好像经常出现在面试题集锦里面,反正我是看见它好多次了。不用加法实现两个数的和,我们可以首先想到位运算,那...

  • Python 入门演示

    简单的数学运算 整数相加,得到整数: 浮点数相加,得到浮点数: 整数和浮点数相加,得到浮点数: 变量赋值 Pyth...

网友评论

    本文标题:2018-01-15 A+B 不用加号实现整数相加

    本文链接:https://www.haomeiwen.com/subject/sttroxtx.html