加减乘除简单吗?不,一点都不,利用位运算实现加减乘除(代码中不含+ - * /)

请添加图片描述

文章目录

  • 🚀前言
  • 🚀异或运算以及与运算
  • 🚀加法的实现
  • 🚀减法的实现
  • 🚀乘法的实现
  • 🚀除法的实现

🚀前言

这也是阿辉开的新专栏,知识将会很零散不成体系,不过绝对干货满满,今天这一篇利用位运算实现加减乘除费了阿辉九牛二虎之力,干的很自备饮水😆不多bb,进入今天的学习吧!!!


以下int均为有符号int,所求的加减乘除也是int类型的整型数
严谨 😏

🚀异或运算以及与运算

在写加减乘除之前,先给铁子们介绍一下异或运算以及与运算的其他理解
异或运算:也叫无进位相加
这怎么理解呢?
铁子们都知道,异或运算,是二进制位相异为1,相同为0

其实异或运算也可以解释为无进位相加。这是什么意思呢?就是对应的二进制位相加,如果产生进位就将进位舍去。什么是进位呢?对应的二进制位相加为2时就向前进一位,就像我们小时候学的加法一样。而二进制进位后,本位就剩下一个0。而在异或运算中,进位被舍去,所以当两个位都为1时,异或的结果为0;当两个位都为0时,异或的结果也为0;只有一个位为1,另一个位为0时,异或的结果才为1

给铁子们上图解释:
请添加图片描述
与运算:得到对应二进制位相加的进位信息右移一位后的结果
怎么理解呢?
铁子们都知道,与运算,是两二进制位都为1为1,一个为0就为0

实际上,与运算是得到对应二进制位相加的进位信息右移一位后的结果,怎么理解呢?二进制位相加时产生的进位保留,没有进位舍去直接置0,然后将得到的结果右移一位。

给铁子们上图解释:

请添加图片描述

🚀加法的实现

有了上述关于异或运算和与运算的新的理解,基于此,我们可以用他们拼凑出加法,怎么拼呢?铁子们接着看👇

根据前面的讲解我们知道,两个数异或运算得到的是两个数相加去掉进位信息后的结果,而两个数与运算得到的是两个数相加保留进位信息右移一位后的结果,铁子们,睁大眼骚操作来了😏,异或运算是去掉进位信息的结果,与运算结果再左移一位(进位信息右移了嘛,再左移回去)是保留进位信息的结果,那两个数异或运算的结果加上两个数与运算再左移一位的结果不就是两个数相加的结果嘛

铁子们一定会说这不还得在加一遍,有毛用,别急还有更骚的😏😏,两个数的异或运算的结果和与运算左移一位的结果,只要与运算左移一位的结果不为0也就是进位信息不为0,得到的俩个数重复上述操作,直到进位信息为0,异或运算的结果不就是两数相加的结果嘛。铁子们,骚不骚?觉得骚的,记得在评论区给阿辉扣个666 😘

肯定有老铁会说难道进位信息一定会计算到0吗?好问题哈哈哈哈 😜,一定会计算到0,为什么呢?阿辉用图说明,鼠标写的铁子们凑合看一下🙏
请添加图片描述

异或运算就是把二进制数相加得到如上述不加上蓝色进位信息的结果,然后和进位信息继续异或,直到不在产生进位信息得到相加的结果

如果还有铁子不懂,可以私聊阿辉加个微信,阿辉必给你搞明白,上面进位信息为啥一定会算到0是阿辉自己想的,自认还有点骚,哈哈哈 😁!
下面就是代码实现了,别看讲了这一堆,其实代码很好写

int Add(int x, int y)//传入需要需要相加的数
{while (y)//y就是进位信息,为0时跳出循环{int a = x ^ y;//利用临时变量保证下一步计算进位信息x不变y = (x & y) << 1;//进位信息x = a;//把去掉进位信息的结果赋给a,重复上述操作}return x;
}

代码就这么短,骚不骚?哈哈哈,这篇博客写的爽,铁子们后面的内容更骚,嘿嘿嘿!!!

🚀减法的实现

减法就没什么技术含量了,因为比如5-4还可以写成5+(-4),套上前面写的加法然后,给减数改成相反数即可
相反数怎么整?让阿辉装一手,嘿嘿

原反补码,阿辉就不讲了,默认大家都会
按位取反操作符~,一个数取反后,符号位会改变,这么一整,该数的正负相反了,符号位以外的数也取反了,如果再加个1,大家不看符号位这不就是负数原码得到补码的过程,哟,这不拿捏了-a = ~a + 1
代码不就好写了:

int Sub(int x, int y)//传入被减数与减数
{return Add(x, ~y + 1);//减数取相反数后与被减数相加
}

🚀乘法的实现

乘法也是稀松平常,没什么难理解的地方,怎么实现呢?铁子们别急,阿辉整个例子你们就懂了👊
请添加图片描述
铁子们这里阿辉,先给出代码再解释:

int Mul(int x, int y)//传进来两数
{int ret = 0;//作返回值for (int i = 0; i <= 30; i = Add(i, 1))//符号位不算,固定循环31次{//遍历y的除符号位的31位,判断是否为1if (y >> i & 1 == 1)//对应二进制位为1,进入if{//因为二进制位只有0和1,0乘任何数还是0,所以不用管//当为1时,1乘任何数还是它本身,所以加上xret = Add(ret, x);}//遍历一次x左移一位,因为再循环,y向后一位找1//这个1代表2的i次方,相当于把这个2的i次方乘在了x上//左移一位相当于乘2,右移一位相当于除2x <<= 1;}return ret;
}

铁子们注意,上述实现的乘法可以计算负数,为什么呢?这与原反补码有关,阿辉水平有限解释不出来,铁子们感兴趣可以研究一下,找到记得和阿辉分享一波,嘿嘿
铁子们,没懂的话可以自己想想试试,如果实在不懂可以私信我好吧,下面的除法才是重头戏特别麻烦 💀

🚀除法的实现

除法比较麻烦,这里阿辉实现的除法是整数除法,上图给大家引导:
请添加图片描述
关于将除法抽象成代码,这是一个相当复杂的过程。首先,让我们回顾一下如何进行除法运算。在我们最常见的十进制系统中,以被除数728÷8为例,我们是如何得出十位上的9的呢?除法运算实际上是在找到一个最大的数,使得将除数8乘以这个数接近被除数728,然后再用728减去这个数720(8×90),然后继续这个过程,要么除尽要么除不尽。不过在整数除法中,如果除不尽就舍去余数。实际上,二进制数的除法运算也是类似的过程。与十进制不同的是,二进制位只有1,因此只需要将除数101后面加上0来逼近被除数101001011(在二进制中,将除数101左移一位就相当于除数后面加上一个0),然后用101001011减去101×1000000(101左移6位),然后重复这个操作直到除尽

但是我们在写代码时不能通过除数左移去逼近,因为这样会有风险
请添加图片描述
红色方块的位置代表符号位。我们给除数b左移,左移一位比a小,继续左移直到比a大才知道上一次左移逼近被除数a。但是对于我们给的这个例子b怎么左移也不可能比a大,因为当b右移11位时,符号位变成1了,b直接变成负数了。
这里我们通过被除数右移代替除数左移来逼近除数达到一样的效果,因为被除数右移多少位逼近除数也就是除数左移多少位逼近被除数,这样就不会有改变符号位的风险
请添加图片描述
我们让除数a从右移14位开始,然后右移位数依次递减,当a右移10位时第一次大于b也就是b左移10位逼近a,然后a减去b左移10位后的数得到的结果重复上述操作第一次找到的就是最高位的1就像我们算十进制除法一样,我们首先找到千位随后就是百位、十位只不过二进制只有0和1很多位都是0

铁子们,下面我会根据代码讲,尽我所能讲明白好吧!
首先,我们实现的除法并不能处理负数,要先把负数处理成正数
这里我们实现一个函数oppo()求相反数

int oppo(int x)//相反数
{return Add(~x, 1);//上面减法的时候解释过了
}

下面是关于除法的具体实现(不包括系统最小值)

int dived(int x, int y)//不含系统最小数的除法
{//负数改正数,正数则不变int a = x < 0 ? oppo(x) : x;//小于0就取相反数int b = y < 0 ? oppo(y) : y;int ret = 0;//作返回值//除了符号位,遍历31次for (int i = 30; i >= 0; i = Sub(i, 1)){//i从30开始依次递减//当a第一次右移i位大于b时,说明最高位的数字找到了//进入if把值加到返回值ret上if (a >> i >= b){ret |= 1 << i;//ret初始值时0,把1或上去a = Sub(a, Mul(b,ret));//同时更新a的值,a=a-b×ret}}//只有x和y不同时为负数或正数时要取相反数//x,y同时大于或小于0,相除就是正数嘛//异或值相等为0嘛就是假//这个异或骚不骚,代替了下面这么挫的代码//if((x > 0 && y < 0) || (x < 0 && y > 0))if (x > 0 ^ y > 0)return oppo(ret);//取相反数return ret;
}

包含系统最小值,int类型的取值为-2^30^ ~ 0 ~ 2^30^-1,因为0是包含在正数里的,所以系统最小值的绝对值大于系统最大值,所以我们面临一个问题,系统最小值没有它的相反数,所以求系统最小值我们要单独拎出来求
五种情况(x是被除数,y是除数):

  • x,y都是系统最小,直接返回1
  • y是系统最小,x不是,直接返回0(整数除法)
  • x是系统最小,y是-1,那结果就是系统最小的绝对值,值域没这个数,直接返回-1
  • x,y都不是系统最小,咱们上面实现的那个代码就是
  • x是系统最小,y不是,这个情况就是我们下面要解决的

x是系统最小,y不是,这里我们无法给它取相反数,我们给x拆成两部分,a=(x+1)得到的就不是系统最小了,用b = (a÷y),可以用我们上面的dived()这个函数来求,然后在用c = x - (b × y),接着a = c ÷ y ,最后a+b就是x÷y的结果
请添加图片描述
就是上面这张图这个原理,没啥难的,不一定要加1,2、3、4……都可以

INT_MIN被宏定义成int类型的最小值,使用需要引<limits.h>头文件

int Div(int x, int y)
{if (x == INT_MIN && y == INT_MIN)return 1;else if (x == INT_MIN && y == -1)return -1;else if (y == INT_MIN)return 0;//这就是上面解释的代码else if (x == INT_MIN){int a = Add(x, 1);int b = dived(a, y);a = dived(Sub(x, Mul(b, y)), y);return Add(a, b);}elsereturn dived(x,y);//不含系统最小值的除法
}

coding有三点要注意:

  • 负数要先转化成正数
  • 被除数左移会有风险
  • 系统最小无法取相反数

加减乘除的完整代码,他们并不是孤立的,互相调用

#include<stdio.h>
#include<limits.h>
int Add(int x, int y)
{while (y){int a = x ^ y;y = (x & y) << 1;x = a;}return x;
}int Sub(int x, int y)
{return Add(x, Add(~y, 1));
}
int Mul(int x, int y)
{int ret = 0;for (int i = 0; i <= 30; i = Add(i, 1)){if (y >> i & 1 == 1){ret = Add(ret, x);}x <<= 1;}return ret;
}int oppo(int x)
{return Add(~x, 1);
}int dived(int x, int y)
{int a = x < 0 ? oppo(x) : x;int b = y < 0 ? oppo(y) : y;int ret = 0;for (int i = 30; i >= 0; i = Sub(i, 1)){if (a >> i >= b){ret |= 1 << i;a = Sub(a, Mul(b,ret));}}if (x > 0 ^ y > 0)return oppo(ret);return ret;
}int Div(int x, int y)
{if (x == INT_MIN && y == INT_MIN)return 1;else if (x == INT_MIN && y == -1)return -1;else if (y == INT_MIN)return 0;else if (x == INT_MIN){int a = Add(x, 1);int b = dived(a, y);a = dived(Sub(x, Mul(b, y)), y);if (x > 0 ^ y > 0)return oppo(Add(a, b));return Add(a, b);}elsereturn dived(x,y);
}

好的,到这里阿辉就讲完了,说实话不容易,着力于构思怎么把铁子们讲懂,应该没有比我更细节的了,写完这篇满满成就感,铁子们觉得讲得不错的话给阿辉评论区扣个666,哈哈哈!!!!
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/215943.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多维时序 | MATLAB实现SAO-CNN-BiGRU-Multihead-Attention多头注意力机制多变量时间序列预测

多维时序 | MATLAB实现SAO-CNN-BiGRU-Multihead-Attention多头注意力机制多变量时间序列预测 目录 多维时序 | MATLAB实现SAO-CNN-BiGRU-Multihead-Attention多头注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现SAO-CNN-B…

CommonJs模块化实现原理ES Module模块化原理

CommonJs模块化实现原理 首先看一个案例 初始化项目 npm init npm i webpack -D目录结构如下&#xff1a; webpack.config.js const path require("path"); module.exports {mode: "development",entry: "./src/index.js",output: {path: p…

硬件开发笔记(十六):RK3568底板电路mipi摄像头接口原理图分析、mipi摄像头详解

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/134922307 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

Redis缓存主要异常及解决方案

1 导读 Redis 是当前最流行的 NoSQL数据库。Redis主要用来做缓存使用,在提高数据查询效率、保护数据库等方面起到了关键性的作用,很大程度上提高系统的性能。当然在使用过程中,也会出现一些异常情景,导致Redis失去缓存作用。 2 异常类型 异常主要有 缓存雪崩 缓存穿透 缓…

【sqli靶场】第二关和第三关通关思路

目录 前言 一、sqli靶场第二关 1.1 判断注入类型 1.2 判断数据表中的列数 1.3 使用union联合查询 1.4 使用group_concat()函数 1.5 爆出users表中的列名 1.6 爆出users表中的数据 二、sqli靶场第三关 2.1 判断注入类型 2.2 观察报错 2.3 判断数据表中的列数 2.4 使用union联合…

什么是 web 组态?web 组态与传统组态的区别是什么?

组态软件是一种用于控制和监控各种设备的软件&#xff0c;也是指在自动控制系统监控层一级的软件平台和开发环境。这类软件实际上也是一种通过灵活的组态方式&#xff0c;为用户提供快速构建工业自动控制系统监控功能的、通用层次的软件工具。通常用于工业控制&#xff0c;自动…

Spring Boot整合 Spring Security

Spring Boot整合 1、RBAC 权限模型 RBAC模型&#xff08;Role-Based Access Control&#xff1a;基于角色的访问控制&#xff09; 在RBAC模型里面&#xff0c;有3个基础组成部分&#xff0c;分别是&#xff1a;用户、角色和权限&#xff0c;它们之间的关系如下图所示 SELECT…

【算法】算法题-20231211

这里写目录标题 一、387. 字符串中的第一个唯一字符二、1189. “气球” 的最大数量三、1221. 分割平衡字符串 一、387. 字符串中的第一个唯一字符 简单 给定一个字符串 s &#xff0c;找到 它的第一个不重复的字符&#xff0c;并返回它的索引 。如果不存在&#xff0c;则返回…

Mockjs 增、删、改、查(分页、多条件查询)

查&#xff08;分页、多条件查询&#xff09;&#xff1a; 关键代码&#xff1a; Mock.mock(/vue-table-list/tableLinkage/list, post, (option) > {// console.log("&#x1f680; ~ file: tableLinkage.js:66 ~ Mock.mock ~ option:", option)const params J…

MFC画折线图,基于x64系统

由于项目的需要&#xff0c;需要画一个折线图。 传统的Teechart、MSChart、HighSpeedChart一般是只能配置在x86系统下&#xff0c;等到使用x64系统下运行就是会报出不知名的错误&#xff0c;这个地方让人很苦恼。 我在进行配置的过程之中&#xff0c;使用Teechart将x86配置好…

基于Java SSM框架实现班级同学录、聚会报名网站系统项目【项目源码+论文说明】

基于java的SSM框架实现班级同学录聚会报名网站系统演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人…

程序员考公笔记之逻辑判断(图形推理)

文章目录 写在前面1、逻辑判断1.1、图形推理1.1.1、位置类1.1.2、样式类1.1.3、数量类1.1.4、属性类1.1.5、六面体 写在前面 1、逻辑判断 1.1、图形推理 观察&#xff1a;先宏观&#xff0c;再微观 图形推理的命题形式&#xff1a; 一组式 观察路径&#xff1a;顺序看(考最…

解决方案- 材料吸波、屏蔽性能测试系统 (10MHz~500GHz)

材料吸波、屏蔽性能测试系统 &#xff08;10MHz~500GHz&#xff09; 材料电磁参数综合测试解决方案 材料吸波、屏蔽性能测试系统测试频率范围可达10MHz&#xff5e;500GHz&#xff0c;可实现材料反射率、屏蔽性能特性参数测试。系统由矢量网络分析仪、测试夹具、系统软件等组…

力扣每日一题day34[110. 平衡二叉树]

给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;t…

wappalyzer基于插件的网站开发技术解析工具

一、wappalyzer 解释&#xff1a;这是一款强大的工具&#xff0c;其主要能提供一种快速、可靠地检测网站所使用技术栈的方法&#xff0c;也就说说&#xff0c;服务器发来的信息都会被它剖析&#xff0c;然后分析出前端的技术栈&#xff0c;有时后端所使用的技术栈如果网页特征…

[ 蓝桥杯Web真题 ]-冬奥大抽奖

目录 介绍 准备 目标 规定 思路 知识补充 解法参考 介绍 蓝桥云课庆冬奥需要举行一次抽奖活动&#xff0c;我们一起做一个页面提供给云课冬奥抽奖活动使用。 准备 开始答题前&#xff0c;需要先打开本题的项目代码文件夹&#xff0c;目录结构如下&#xff1a; ├──…

甲醛处理企业网站效果如何

甲醛往往是新装房间主所担心的问题&#xff0c;而甲醛处理公司则可以处理甲醛问题&#xff0c;市场需求也比较高&#xff0c;虽然具备同城服务属性&#xff0c;但外地或连锁经营也非常适合&#xff0c;而品牌们也遇到一些痛点&#xff1a; 1、品牌宣传拓客难 甲醛处理公司也需…

基于查表法的水流量算法设计与实现

写在前面 本文分享的是一种基于查表法的水流量的算法方案设计与实现&#xff0c;算法简单易懂&#xff0c;主要面向初学者&#xff0c;有两个目的&#xff1a;一是给初学者一些算法设计的思路引导&#xff1b;二是引导初学者学习怎样用C语言编程实现。 一、设计需求 基于“19…

液态二氧化碳储存罐远程无线监测系统

二氧化碳强化石油开采技术&#xff0c;须先深入了解石油储层的地质特征和二氧化碳的作用机制。现场有8辆二氧化碳罐装车&#xff0c;每辆罐车上有4台液态二氧化碳储罐&#xff0c;每台罐的尾部都装有一台西门子S7-200 smart PLC。在注入二氧化碳的过程中&#xff0c;中控室S7-1…

OneNote for Windows10 彻底删除笔记本

找了超多方法&#xff0c;都没有用&#xff0c;我的OneNote都没有文件选项&#xff0c;要在OneDrive中删除&#xff0c;但是一直登不进&#xff0c;然后又找到一个方法&#xff1a; 在网页中打开Office的控制面板 "Sign in to your Microsoft account" 在“最近”一…