如何用计算机算电路,计算机底层是如何计算加法的?

众所周知在计算机中,所有的数据都是通过电信号表示的,自然加法计算也是通过电信号来进行表达过程和结果的,高电平表示1低电平表示0,也就是二进制数,如果我们要计算11+21=?,换算为二进制数即1011+10101=?

为什么使用二进制

已知电信号是通过二极管控制电流输出表示,计算机通过控制二极管的输出电流大小对应不同的状态值,早期的计算器出现了对应三种状态、五种状态的电路,也就是三进制计算机,五进制计算机,但是状态越多,就越难区分信号,当外界有干扰的时候,电信号可能会混乱在一起,晶体管本身就是高速运作的元件,会让混乱的情况更严重,为了尽可能减少这类问题的发生,只用高电平和低电平表示两种状态,也就是打开和关闭,这样大大的减少了出错的可能。

b3214400ae155c0342f7bc97b621e2b8.png

并且刚好在数学领域有一门分支,叫做布尔代数,用数学公式演算了很多逻辑运算,基本运算符有NOR、AND、OR,输出的值均为true和false,刚好匹配上晶体管电路控制中的开和关,下面是各个基础逻辑门的真值表:

32abbb91fdacc5c368d6f0ec80586e22.png

半加器和全加器

有了逻辑门之后,就可以开始计算二进制位之间的加法,当10111+10101从低位第一次相加的时候,需要计算两个二进制数1和1加法,根据满二进一的原则,加法结果sum=0,需要向前进位carry=1,对应电路为,两个输入位A和B,两个输出位SUM和CARRY。

通过观察可以发现,当两个输入位A和B都为1或者0时sum=0,其他时候sum=1,正好对应XOR门的输出,所以XOR的输出即为SUM,并且当且仅当两个输入位A和B都为1时,才需要进位carry=1,对应AND门的输出,所以AND门的输出即为carry,整个电路即半加器:

9f840e180161db6c26c0cc3e14beba3e.png

68e885227ca04236343803b6d246e20e.png

对应js代码:// 半加器,&代表and门,^代表XOR门const halfAdder = (a: number, b: number) => [a & b, a ^ b];复制代码

计算完最低位往左移,计算10111+10101中的1+0,此时需要计算两个加数1和0,加上低位上的进位1,才能输出一个结果sum和一个进位carry,基于半加器的实现,需要先计算出a+b的sum1和carry1,然后与低位的进位进行一次半加器运算得到sum2和carry2,sum2即最终的sum输出,最后再用OR门判断第二次半加器运算的carry2和第一次运算的carry1是否有进位,只要有进位就输出carry=1,整个电路即全加器:

2ef5e63c8aabb5112061e7670ae64782.png

对应js代码:// 全加器,|代表OR门const fullAdder = (a: number, b: number, carry: number) => (

([a, b] = halfAdder(a, b)), ([carry, b] = halfAdder(b, carry)), [a | carry, b]

);复制代码

有了半加器和全加器,只需要把各个位上的输入链接到对应的半加器或者全加器上,然后接通电源就能得到最终的输出,电路即:

b10db819e85842e4e35354463a917198.png

代码实现

有了基础实现,只要需要根据逻辑编写代码即可:// 半加器const halfAdder = (a: number, b: number) => [a & b, a ^ b];// 全加器const fullAdder = (a: number, b: number, carry: number) => (

([a, b] = halfAdder(a, b)), ([carry, b] = halfAdder(b, carry)), [a | carry, b]

);// 位加法计算器const bitsAdder = (addend1: number, addend2: number) => {  let addend1Bits: string = addend1.toString(2);  let addend2Bits: string = addend2.toString(2);  let maxLength = 0;  // 补0

addend1Bits.length >= addend2Bits.length

? ((maxLength = addend1Bits.length - 1), (addend2Bits = addend2Bits.padStart(addend1Bits.length, '0')))

: ((maxLength = addend2Bits.length - 1), (addend1Bits = addend1Bits.padStart(addend2Bits.length, '0')));  // 避免重复创建变量

let aBit = 0;  let bBit = 0;  let tempCarry = 0;  let tempSum = 0;  let result: number[] = [];  let index = maxLength;  while (index > -1) {

aBit = +addend1Bits[index];

bBit = +addend2Bits[index];

[tempCarry, tempSum] = index === maxLength ? halfAdder(aBit, bBit) : fullAdder(aBit, bBit, tempCarry);

result.unshift(tempSum);

index--;

}  // 记得插入最后一个进位

result.unshift(tempCarry);  console.log(parseInt(result.join(''), 2));

};复制代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值