zoukankan      html  css  js  c++  java
  • 不用加减乘除做加法

    题目

      写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

    思路

      二进制中,两个数相加有如下的规律

    1. 如果对应的位上都为1,那么该位上就要归零,并且往左侧进一位;
    2. 如果对应的位数不全都是1(1/0, 0/1, 0/0三种情况),那么该位在相加时,如果是1/0,或者0/1,就可置为1,如果是0/0,那就置为0。

    所以有如下解法:

    1. 先将各bit位相加,不计进位,用异或实现
    2. 加上进位,用与运算,全为1与之后为1,而不全为1的位则全部变为了0,该位相加会发生进位,使得左边一位加1,因此(m&n)<<1边可得到进位后要加的1的位置
    3. 将前面两步的结果相加,相加的时候还有可能再产生进位,因此二者相加的过程可以再次重复循环步骤1和2,直到(m&n)<<1变为了0,这时候不会再产生进位,退出循环。
    #include <iostream>
    using namespace std;
    
    class Solution
    {
        public:
            int add(int num1,int num2);
    };
    int Solution::add(int num1,int num2)
    {
        int sum=0,carry=0;
        do
        {
            sum=num1^num2;
            carry=(num1&num2)<<1;
            num1=sum;
            num2=carry;
        }while(num2!=0); 
        return num1;
    }
    
    int main()
    {
        Solution s;
        cout<<s.add(3,3)<<endl; 
        return 0;
    }

     拓展

      不定义新的变量交换两变量的值。

      1.基于加法

    void swqp(int a,int b)
    {
        a=a+b;
        b=a-b;
        a=a-b;
    }

      2.基于异或运算

    void swap(int a,int b)
    {
        a=a^b;
        b=a^b;
        a=a^b;
    }

     用这个办法交换2个指针的内容.那么你要先检查2个指针指向的地址是否相同.不然会导致内容被清0

      3.不用加减乘除做减法

    1. 首先,如果减数为0,则被减数即为减法的结果,运算结束。
      但如果减数不为0,我们可以先把被减数和减数上同为1的位从两个数上去除。至于如何分离出值同为1的位,则可以通过求位与操作来做到;而把这些1分别中被减数和减数中去除,则可以通过按位异或来的操作来实现。
    2. 经步骤1处理后,被减数和减数在对应的位上,将或者通为0,或者分别为0和1,却不会同为1。此时:
      如果对应位被减数=1,而减数=0,则所得结果对应位也为1;
      如果对应位被减数=0,而减数=1,则所得结果对应位还是1,但此时须向前一位借1;
      即,通过被减数与减数作位异或的操作得到临时结果,和通过对减数左移一位得到需从临时结果中减去的借数。
    3. 于是,经过步骤2后,原来的减法变成了要求:临时结果 - 借数
      很明显,只要以临时结果为被减数,借数为减数,重复步骤1~3即可。
    #include <iostream>
    using namespace std;
    
    class Solution
    {
        public:
            int add(int num1,int num2);
            int sub(int num1,int num2);//方法1 
            int sub1(int num1,int num2);//方法2 
    };
    int Solution::add(int num1,int num2)
    {
        int sum=0,carry=0;
        do
        {
            sum=num1^num2;
            carry=(num1&num2)<<1;
            num1=sum;
            num2=carry;
        }while(num2!=0); 
        return num1;
    }
    int Solution::sub(int num1,int num2)
    {
        //反码:解决负数加法运算问题,将减法运算转换为加法运算,从而简化运算规则
        //补码:解决负数加法运算正负零问题,弥补了反码的不足
        //减去一个数等于加上这个数的补码,把减法转化为加法运算 
        //求补码:原码每位取反末尾+1 
        return add(num1,add(~num2,1));
    }
    int Solution::sub1(int num1,int num2)
    {
        while(num2!=0)
        {
            int temp=num1&num2;//1-1得0,计算每个标记两个数都为1的位 
            num1^=temp;//清除被减数为1的位 
            num2^=temp;//清除减数为1的位 
            num1|=num2;
            num2<<=1;
        }
        return num1;
    }
    int main()
    {
        Solution s;
        cout<<s.sub(3,2)<<endl; 
        cout<<s.sub1(3,2)<<endl;
        return 0;
    }

     code

    class Solution {
    public:
        int Add(int num1, int num2)
        {
            _asm
            {
                MOV EAX,num1
                MOV ECX,num2
                ADD EAX,ECX
            }
        }
    };
  • 相关阅读:
    怎样监听HTTP请求的发出与完成
    在Ubuntu下安装source Insight
    Android 5.1 预制输入法
    RK3288编译 Android 5.1 固件
    Android编程之Listener侦听的N种写法及实现原理
    android thread Runnable
    Android Service完全解析(下)
    Android Service完全解析(上)
    android 串口 android-serialport-api
    Android Studio在Ubuntu下离线安装Gradle
  • 原文地址:https://www.cnblogs.com/tianzeng/p/10326705.html
Copyright © 2011-2022 走看看