可软可硬——从电路的角度做加法

简介: 可软可硬——从电路的角度做加法

摄影:产品经理跟产品经理的吃吃喝喝

最近在听《三体》的广播剧,今天刚好讲到人列计算机。电路设计是我大学的老本行,后来却跑去做软件,真让人唏嘘。今天,我们就从逻辑电路的角度来讲一讲,加法是怎么实现的。

我们知道,5+9=14,这是再简单不过的一个加法。稍稍懂一些计算机的同学也知道,数字在计算机里面是二进制形式存放的,所以显然5+9在计算机里面是101 + 1001 = 1110

相信很多人到这一步就停下来了,就拿出去装逼了。

那么我们更进一步,二进制101和二进制1001在电路里面,到底是怎么做加法的?我们知道电路的导通表示1,电路的关闭表示0.现在给你一个几个开关,你能通过改变它的导通和关闭来做加法吗?

为了使用电路来做加法,我们需要知道三个电路元件:与门或门异或门。这三个门都有两个输入脚和一个输出脚。两个输入脚是否通电决定了输出脚是否通电。他们长下面这样:

与门

对于与门,只有两个输入引脚同时有电流流入,输出脚才有电流流出。否则输出脚没有电流流出。相当于 Python 里面的and关键字。

或门

对于或门,任何一个输入脚有电流流入或者两个脚同时有电流流入,输出脚都有电流流出。相当于 Python 里面的or关键字。

异或门

对于异或门,当两个输入引脚中,只有一个引脚有电流流入时,有电流流出。但是如果两个引脚同时有电流流入,或者同时没有电流流入,输出引脚都没有电流流出。相当于Python 里面的^符号。

那么如和使用这三种逻辑门电路,组合出一个做加法的电路呢?我们来看一下一位的二进制加法。

  • 0 + 0 = 0
  • 0 + 1 = 1
  • 1 + 0 = 1
  • 1 + 1 = 0 并进1位。

如果不考虑进位,实际上这个结果就是异或门的结果。所以我们可以直接使用一个异或门,来表示1位二进制的加法。但由于最后的结果只有一个二进制位来存放,所以进位的1就丢失了。

现在我们来考虑,如何保留这个进位的1呢?注意到,只有两个1 + 1这一种情况才会出现进位。所以我们需要有一个电路,只对1 + 1起反应,而对另外三种不起反应。

显然,我们可以使用与门,只有在两个输入引脚都有电流流入的时候,才会有电流流出。我们通过这个与门是否有电流流出就能判断是否有进位发生。如下图所示:

与门异或门并联,实现记录相加的结果和进位信息。

现在我们增加一下难度,如果是两个二位二进制数相加呢?对于低位的二进制数数,显然我们上面的做法已经可以了。但是对于高位的二进制数而言,不仅本身要相加,还要加上低位进上来的进位数。所以要到高位异或出来的结果再与低位的进位输入再异或一次。并且这个和也要考虑是否进位。如下图所示:

为什么最后还有一个或门呢?是因为,进位有三种情况下是进1,还有一种情况下是进0.

高位的被加数(a)、加数(b)他们本身的进位可能是0或者是1. a 和 b 的和再与低位进位数(c)再求和,新的进位可能是0或者是1。但需要注意,当 a与 b 需要进1的时候,a 与 b 的和必定为0.此时与c的和不可能进位。只有当 a 与 b 一个是0,一个是1的时候,他们本身的进位是0,但他们在 c 为1的时候新的进位是1。

所以最后两个进位的输出汇入一个或门得到最终的进位输出,成为新的进位。

我们发现,第一副图实际上就是第二幅图在 c=0时候的特殊情况。所以只有一位数做加法的时候,也可以使用第二幅图对应的电路。

当我们把4个这样的电路连在一起的时候,也就实现了一个4位的全加器。

我们通过 Python 来模拟这个电路:

def full_add(a, b, c):    sum_of_a_b = a ^ b    final_sum = sum_of_a_b ^ c    increase_of_a_b = a & b    increase_of_sum_of_a_b_c = sum_of_a_b & c    final_increase = increase_of_a_b | increase_of_sum_of_a_b_c    return final_sum, final_increase

我们使用两个数字来测试一下这个全加器:

这个结果最后输出的数字,我们从下往上读,就是1110,正好是14对应的二进制数,说明计算成功。

我们再来个复杂的,1099 + 237 =  1336,运行效果如下图所示:

从下往上读,确实是正确的:

大家注意,我最后把进位的数打印了出来。并且通过一个while循环,无论加数和被加数有多少位都进行计算。但是在实际电路中,或者 C 语言中,我们需要定义整型的长度,例如32位整型,64位整型等等。那么,当最后的进位超出了这个最大位数,如果是无符号整型,就会发现两个很大的数相加结果竟然是一个很小的数,因为最后的进位1由于超过了最大位数,被丢掉了;如果是有符号整型,就会发现两个正数相加变成了负数,因为最高位本来是0,由于进位的关系,它变成了1,但最高位是1表示负数。

这两种情况就叫做数值溢出。

目录
相关文章
|
前端开发 微服务
Element-Plus 表格 el-table 如何支持分页多选
Element-Plus 表格 el-table 如何支持分页多选
|
存储 Shell 网络安全
docker 安装gitlab,配置邮件,备份全流程
docker 安装gitlab,配置邮件,备份全流程
739 0
docker 安装gitlab,配置邮件,备份全流程
|
数据采集 数据可视化 数据挖掘
Python数据挖掘项目实战——自动售货机销售数据分析
Python数据挖掘项目实战——自动售货机销售数据分析
|
4月前
|
Java 应用服务中间件 Maven
在IntelliJ IDEA中如何配置使用Maven以创建Tomcat环境
所以,别担心这些工具看起来有些吓人,实际上这些都是为了帮助你更好的完成工作的工具,就像超市里的各种烹饪工具一样,尽管它们看起来可能很复杂,但只要你学会用,它们会为你烹饪出一道道美妙的食物。这就是学习新技能的乐趣,让我们一起享受这个过程,攀登知识的高峰!
322 27
|
5月前
|
数据采集 Web App开发 文字识别
Python爬虫多次请求后被要求验证码的应对策略
Python爬虫多次请求后被要求验证码的应对策略
|
9月前
|
移动开发 前端开发 Java
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
JavaFX是Java的下一代图形用户界面工具包。JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序。 JavaFX允许开发人员快速构建丰富的跨平台应用程序,允许开发人员在单个编程接口中组合图形,动画和UI控件。本文详细介绍了JavaFx的常见用法,相信读完本教程你一定有所收获!
8821 5
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
|
应用服务中间件 nginx 微服务
SpringCloud解决feign调用token丢失问题
【5月更文挑战第2天】在feign调用中可能会遇到如下问题: * 同步调用中,token丢失,这种可以通过创建一个拦截器,将token做透传来解决 * 异步调用中,token丢失,这种就无法直接透传了,因为子线程并没有**token**,这种需要先将token从父线程传递到子线程,再进行透传
1040 3
|
12月前
|
Unix 网络虚拟化 C++
VS2022+Qt5.14.2成功编译MITK2022.10
使用VS2022和Qt5.14.2成功编译MITK2022.10的过程,包括编译结果的截图、遇到的编译问题的解决方法、两个重要的注意事项(patch文件格式的修改和ITK-gitclone-lastrun文件的存在),以及参考链接。文中详细描述了如何解决编译过程中遇到的错误C2220和警告C4819,以及如何修改文件编码和尾行格式。
793 1
VS2022+Qt5.14.2成功编译MITK2022.10
|
消息中间件 物联网 Kafka
消息队列 MQ产品使用合集之QoS 1与QoS 2的主要区别有哪些
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
缓存 算法 网络架构
【网络层】IP组播(多播)、硬件组播、IGMP、组播路由选择协议、移动IP、路由器详解、路由表和路由转发
【网络层】IP组播(多播)、硬件组播、IGMP、组播路由选择协议、移动IP、路由器详解、路由表和路由转发
331 0