这个题是leetcode里面的一个经典面试题,整理了几种比较经典的实现方法。

1、加法

  要实现加法操作可以分为两步:

 (1)不进位部分的加法用a^ b;

 (2)进位部分的加法用(a&b)<<  1;

递归实和非递归现方法实现如下:


//加法
//(递归方法)
int getAddNumber(int a, int b)
{if (b == 0) return a;int sum = a^b;//可以得到进位int carray = (a & b) << 1;return  getAddNumber(sum, carray);
}
//(非递归方法)
int getAddNumber1(int a, int b) {while (b) {// 防止 AddressSanitizer 对有符号左移的溢出保护处理auto c = ((unsigned int)a & b) << 1;a = a ^ b;b = c;}return a;
}
int getAddNumber2(int a, int b) {int sum;int carry;if (a == 0) return b;if (b == 0) return a;carry = a & b;sum = a ^ b;while (carry) {int temp = sum;//最高位为1即负数左移会报错, 使carry最高位永远为0carry = carry & (-1);sum = sum ^ (carry << 1);carry = temp & (carry << 1);}return sum;
}

2、减法

要实现减法首先的有补码相关的知识:补码相关知识

  我们分以下几步来看:(以a - b为例)

  (1) 如果b 的值为0,那么结果显而易见就是a 了。

  (2) b 不为0 的情况下,我们仍然先不考虑借位,先将被减数和减数同为1 的位置去掉。

    第一步,找出减数和被减数同为1 的位置。可使用 sameNum = a&b;

    第二步,分别将被减数和减数同为1 的位置去掉1 ,这里可以用

a ^= sameNum; b ^= sameNum;

  (3) 此时,减数和被减数相同位只存在以下三种情况:

    1. 被减数:0 ;减数: 0;差:0;
    2. 被减数:0 ;减数: 1;差:1;
    3. 被减数:1 ;减数: 0;差:1;

  (4) 通过对被减数、减数和差的分析,很容易就能知道差值应该是被减数和减数的按位或的结果。于是我们便有:a | b 得到临时的结果;

  (5) 此时再考虑借位问题。很明显只有在减数为1的情况下,被减数与之对应的左一位才会出现借位,于是借位便可以用 b << 1 ; 来表示。

  (6) 再把临时结果减去借位,直到借位为0,得到的结果便是最终的结果了。

//减法
int getSubNUm(int a, int b)
{while (b != 0){// 去掉被减数和减数中同为1的位int sameNum = a & b;a ^= sameNum;b ^= sameNum;// 此时,a 和 b 不存在同时为1 的位// 0 - 1 和 1 - 0 都为1a |= b; // 得到相减的临时结果(不考虑借位)b = b << 1; // 减数为1 时,必有借位}return a;
}

3、乘法

(1)先考虑正整数之间的乘法运算

  在二进制中,每向左移动一次,都相当于原始数乘以2。而每个数据都可以写成k0×20+k1×21+...+km×2m的形式。因此我们可以得到以下式子:

  a x b = ax20xk0 +  ax21xk1 + .... + ax2mxkm 其中ki = {0, 1};

(2)其次就是要考虑正负号(溢出问题)

这里可以直接判断a、b和0 的关系来判断正负,也可以做左移操作,因为计算机中数据都是以补码的数据存储的,其中正数和负数的区别便是最高位是否为1;(负数的补码最高位为1);


int maxNumFlag()
{int bitsOfByte = 8;int maxNum = 0x80;int tmp = maxNum;while (tmp != 0){maxNum = tmp;tmp <<= bitsOfByte;}return maxNum;
}//乘法
int getMultip(int a, int b)
{// 1.先只考虑正整数的相乘// 2.考虑正负情况和溢出问题int maxNum = maxNumFlag();int flag_a = 1;if ((maxNum & a) != 0){flag_a = 0; // 负数a = getAddNumber(~a, 1);}int flag_b = 1;if ((maxNum & b) != 0){flag_b = 0;b = getAddNumber(~b, 1);}int result = 0;for (int bits = 1; bits != 0; bits <<= 1){if ((bits & b) != 0){result = getAddNumber(result, a);if ((result & maxNum) != 0|| (a & maxNum) != 0){cout << "数据过大!" << endl;}}a <<= 1;}return (flag_a ^ flag_b) == 0 ? result : getAddNumber(~result, 1);
}

4、除法

第一种方法:除法没有溢出,但是有其他的限定条件,比如除数不能为“0”。

  这里先说下除法和减法之间的关系。以97÷23=4(余5)为例:

  也就是 97-23×4=5

:=》97-23-23-23-23 = 5

//除法
int getDivision(int a, int b)
{if (b == 0){cout<< "除数不能为0!!"<< endl;}int maxNum = maxNumFlag();int flag_a = 1;if ((maxNum & a) != 0){flag_a = 0; // 负数a = getAddNumber(~a, 1);}int flag_b = 1;if ((maxNum & b) != 0){flag_b = 0;b = getAddNumber(~b, 1);}int index = 1;int tmp = getSubNUm(a, b);if (tmp < 0){return 0;}while (tmp >= b){tmp = getSubNUm(tmp, b); // 最后一次循环后的tmp 便是a/b 的余数index = getAddNumber(index, 1);}return (flag_a ^ flag_b) == 0 ? index : getAddNumber(~index, 1);
}

 第二种方法:思路如下:

    1. 预备工作:置商为0;
    2. 判断“被除数>=除数 ”是否成立:

成立,继续步骤3;

不成立,被除数的值赋给余数,计算结束。

    1. 备份除数,并设置商分子(一个临时变量,最终需加到商上面,故暂且如此命名)为1;

对商分子和除数同步向左移位,直到继续移位将大于被除数时为止;

    1. 从被除数上减去除数,并将商加上商分子。
    2. 通过备份的除数值还原除数,跳转到步骤2继续执行。
int getDivision1(int a, int b)
{if (b == 0){cout<< "除数不能为0!!"<< endl;}int maxNum = maxNumFlag();int flag_a = 1;if ((maxNum & a) != 0){flag_a = 0; // 负数a = getAddNumber(~a, 1);}int flag_b = 1;if ((maxNum & b) != 0){flag_b = 0;b = getAddNumber(~b, 1);}int quotient = 0;int backupB = b;while (a >= b){int tempB = b << 1;int tempQ = 1;while ((tempB <= a) && ((tempB & maxNumFlag()) == 0)){b = tempB;tempQ <<= 1;tempB <<= 1;}a = getSubNUm(a, b);quotient |= tempQ;b = backupB;}if (((maxNum & a) != 0) && (a != 0)){quotient = getAddNumber(quotient, 1);}return (flag_a ^ flag_b) == 0 ? quotient : getAddNumber(~quotient, 1);
}

完整实现的代码:

#include <iostream>
using namespace std;//加法
//(递归方法)
int getAddNumber(int a, int b)
{if (b == 0) return a;int sum = a^b;//可以得到进位int carray = (a & b) << 1;return  getAddNumber(sum, carray);
}
//(非递归方法)
int getAddNumber1(int a, int b) {while (b) {// 防止 AddressSanitizer 对有符号左移的溢出保护处理auto c = ((unsigned int)a & b) << 1;a = a ^ b;b = c;}return a;
}
int getAddNumber2(int a, int b) {int sum;int carry;if (a == 0) return b;if (b == 0) return a;carry = a & b;sum = a ^ b;while (carry) {int temp = sum;//最高位为1即负数左移会报错, 使carry最高位永远为0carry = carry & (-1);sum = sum ^ (carry << 1);carry = temp & (carry << 1);}return sum;
}
//减法
int getSubNUm(int a, int b)
{while (b != 0){// 去掉被减数和减数中同为1的位int sameNum = a & b;a ^= sameNum;b ^= sameNum;// 此时,a 和 b 不存在同时为1 的位// 0 - 1 和 1 - 0 都为1a |= b; // 得到相减的临时结果(不考虑借位)b = b << 1; // 减数为1 时,必有借位}return a;
}int maxNumFlag()
{int bitsOfByte = 8;int maxNum = 0x80;int tmp = maxNum;while (tmp != 0){maxNum = tmp;tmp <<= bitsOfByte;}return maxNum;
}//乘法
int getMultip(int a, int b)
{// 1.先只考虑正整数的相乘// 2.考虑正负情况和溢出问题int maxNum = maxNumFlag();int flag_a = 1;if ((maxNum & a) != 0){flag_a = 0; // 负数a = getAddNumber(~a, 1);}int flag_b = 1;if ((maxNum & b) != 0){flag_b = 0;b = getAddNumber(~b, 1);}int result = 0;for (int bits = 1; bits != 0; bits <<= 1){if ((bits & b) != 0){result = getAddNumber(result, a);if ((result & maxNum) != 0|| (a & maxNum) != 0){cout << "数据过大!" << endl;}}a <<= 1;}return (flag_a ^ flag_b) == 0 ? result : getAddNumber(~result, 1);
}//除法
int getDivision(int a, int b)
{if (b == 0){cout<< "除数不能为0!!"<< endl;}int maxNum = maxNumFlag();int flag_a = 1;if ((maxNum & a) != 0){flag_a = 0; // 负数a = getAddNumber(~a, 1);}int flag_b = 1;if ((maxNum & b) != 0){flag_b = 0;b = getAddNumber(~b, 1);}int index = 1;int tmp = getSubNUm(a, b);if (tmp < 0){return 0;}while (tmp >= b){tmp = getSubNUm(tmp, b); // 最后一次循环后的tmp 便是a/b 的余数index = getAddNumber(index, 1);}return (flag_a ^ flag_b) == 0 ? index : getAddNumber(~index, 1);
}int getDivision1(int a, int b)
{if (b == 0){cout<< "除数不能为0!!"<< endl;}int maxNum = maxNumFlag();int flag_a = 1;if ((maxNum & a) != 0){flag_a = 0; // 负数a = getAddNumber(~a, 1);}int flag_b = 1;if ((maxNum & b) != 0){flag_b = 0;b = getAddNumber(~b, 1);}int quotient = 0;int backupB = b;while (a >= b){int tempB = b << 1;int tempQ = 1;while ((tempB <= a) && ((tempB & maxNumFlag()) == 0)){b = tempB;tempQ <<= 1;tempB <<= 1;}a = getSubNUm(a, b);quotient |= tempQ;b = backupB;}if (((maxNum & a) != 0) && (a != 0)){quotient = getAddNumber(quotient, 1);}return (flag_a ^ flag_b) == 0 ? quotient : getAddNumber(~quotient, 1);
}int main()
{cout << getAddNumber(-2, 8) << endl;cout << getAddNumber1(10, 999999) << endl;cout << getAddNumber2(-2, -30) << endl;cout << getSubNUm(100, -3) << endl;cout << getMultip(-30, 6) << endl;cout << getDivision(42,3) << endl;cout << getDivision(9,2) << endl;return 0;
}

不用标点符号实现加减乘除运算相关推荐

  1. C---编写程序:实现一个随堂测试,能进行加减乘除运算。要求如下:(1)随机产生两个1~10的正整数,在屏幕上输出题目,如:5+3=?(2)学生输入答案,程序检查学生输入答案是否正确,若正确,

    编写程序:实现一个随堂测试,能进行加减乘除运算.要求如下: 1)随机产生两个1~10的正整数,在屏幕上输出题目,如:5+3=? 2)学生输入答案,程序检查学生输入答案是否正确,若正确,则输出" ...

  2. java float 加法_JAVA 实现精确的加减乘除运算

    JAVA在加减乘除运算时易发生精度丢失,达不到我们想要的计算结果:为了能够精确表示.计算浮点数,JAVA提供了BigDecimal类,可以以BigDecimal为基础定义一个Arith工具类,代码如下 ...

  3. 简单工厂模式--加减乘除运算

    下面基于简单的<加减乘除运算>实例来讲讲实用简单工厂模式:<备注:以后根据认识的加深,可以添加和修改内容> 需求分析:希望程序提供"加减乘除"四种功能. 功 ...

  4. java用流体加减乘除_任意输入两个数,完成加法、减法、乘法、除法运算!(加减乘除运算分别定义四个方法)_学小易找答案...

    [简答题]编写程序实现菜单设计 [简答题]一层平面图 [简答题]编写一个程序实现大小写字母转换 [简答题]利用循环语句输出一个五行的等腰三角形,如下图 [简答题]编写一个程序实现交换两个变量的数值. ...

  5. matlab 矩阵加减乘除运算

    文章目录 matlab 矩阵加减乘除运算 1 .加.减运算 2. 乘法 3.向量点积 4.向量叉乘 5.混合积 6.矩阵的卷积和多项式乘法 7.反褶积(解卷)和多项式除法运算 8.张量积 9. 除法运 ...

  6. [基础题]2.(*)利用接口做参数,写个计算器,能完成加减乘除运算。

    /*2.(*)利用接口做参数,写个计算器,能完成加减乘除运算. (1)定义一个接口Compute含有一个方法int computer(int n, int m). (2)设计四个类分别实现此接口,完成 ...

  7. sql的加减乘除运算_SQL简单查询语、运算符学习和练习

    本次主要学习了SQL语言的书写和运算,多为实操,一定要多写多思考,综合运用起来. 基本查询语句(select *全部 as替换 distinct删除重复) 指定查询条件(where 从哪里查询) 注释 ...

  8. 关于浮点型加减乘除运算不精确的问题

    关于浮点型加减乘除运算不精确的问题 先举一个遇到这个错误的项目例子: 之前做一个小模块,由于后端接口还没有完成,需要自己搭建node服务,返回数据,功能需求是实时更新的,这个小模块中本人没有使用web ...

  9. 51单片机实现三位十进制数加减乘除运算

    51单片机实现三位十进制数加减乘除运算 一.题目 51单片机IO接口作业 请将附件给出的Proteus图用51单片机完成一个计算器功能. 1.显示采用动态分时8位共阳数码管输出. 2.采用4*4矩阵键 ...

最新文章

  1. 如何解读和在线绘制进化树?
  2. JAVA基础12-继承(3)
  3. 基于JSP实现的项目管理平台系统
  4. 在食堂吃饭是最好的解
  5. 五分钟的JShell
  6. java 16 binary_【图片】【困扰】java(tm) platform se binary 已停止工作该如何是好【minecraft吧】_百度贴吧...
  7. JS特效代码大全(十一)超炫的js图片展示效果(三)
  8. Matlab画箭头arrow.m
  9. 以鶸ice为例,手撸一个解释器(一)明确目标
  10. linux 多线程学习
  11. Java抓取淘宝/天猫商品详情 1
  12. java中double类型占几个字节_Java中的单双精度数据类型分别占几个字节?
  13. Cf#595 (Div. 3)D-贪心
  14. Linux 下的桌面指针时钟
  15. Android组件化入门,分享一点面试小经验
  16. spring boot 作业管理系统
  17. 单片机(3)跑马灯,按钮控制的跑马灯(2种编程)
  18. 当前安装包签名出现异常_关于部分华为手机安装游戏提示“签名异常”问题说明...
  19. 树莓派显示到笔记本屏幕上
  20. 安全模式怎么更改计算机用户,电脑怎么关闭安全模式步骤详解

热门文章

  1. 格子玻尔兹曼机(Lattice Boltzmann Method)系列3:LBM在不可压缩流动下的边界条件算法
  2. 这几行码是什么意思呢
  3. 判断身份证号码的正确性源码
  4. 多个git账号的登录与切换
  5. 超越Yann LeCun:世界模型的学习和推理
  6. ubuntu修改时区
  7. 十大城市男人魅力新榜 [转帖]
  8. 如何整理个人电脑的文件及目录?(第1期)
  9. springboot高校失物招领系统的设计与实现毕业设计源码121441
  10. kube-controller-manager源码分析(三)之 Informer机制