JS模拟实现串行加法器

Oria ·
更新时间:2024-11-15
· 513 次阅读

在重温《编码:隐匿在计算机软硬件背后的语言》第12章——二进制加法器时,心血来潮用JS写了一个模拟串行加法器。

测试断言工具TestUtils.js

function assertTrue(actual){     if(!actual)         throw "Error actual: " + actual + " is not true." } function assertFalse(actual){     if(actual)         throw "Error actual: " + actual + " is not false." } function assertIntEquals(expected, actual){     if(typeof expected != "number")         throw "Error expected: " + expected +" is not a number."     if(typeof actual != "number")         throw "Error actual: " + actual +" is not a number."     if(expected != actual)         throw "Error expected: " + expected + " and actual: " + actual +" is different." }

十进制数与二进制数之间转换工具utils.js

function int2LowEightBitArray(num){     var result = []     for(var i = 0; i < 8; i++)         result.push(((num >> i) & 1) == 1)     return result } function lowEightBitArray2Int(array){     var result = 0     for(var i = 0; i < 8; i++){         if(array[i])             result += (1 << i)     }     return result } function lowNineBitArray2Int(array){     var result = 0     for(var i = 0; i < 9; i++){         if(array[i])             result += (1 << i)     }     return result } //用补码表示负数 function int2EightBitArray(num){     if(num < -128 || num > 127){         throw "Out of boundary(-128, 127)."     }     var result = []     for(var i = 0; i < 8; i++)         result.push(((num >> i) & 1) == 1)     return result } function eightBitArray2Int(array){     var result = 0     for(var i = 0; i < 7; i++){         if(array[i])             result += (1 << i)     }     if(array[i])         result += -128     return result } function int2SixteenBitArray(num){     if(num < -(1 << 15) || num > (1 << 15) - 1){         throw "Out of boundary({left}, {right})."             .replace("{left}", -(1 << 15))             .replace("{right}", (1 << 15) - 1)     }     var result = []     for(var i = 0; i < 16; i++)         result.push(((num >> i) & 1) == 1)     return result } function sixteentBitArray2Int(array){     var result = 0     for(var i = 0; i < 15; i++){         if(array[i])             result += (1 << i)     }     if(array[i])         result += -(1 << 15)     return result }

加法器模型model.js

class DoubleInGate{     #id     #in1     #in2     #gateTypeName     #func     #out     #lastOut     #outReceiver     #outReceiverInName     constructor(id, gateTypeName, in1 = false, in2 = false, func){         this.#id = id         this.#gateTypeName = gateTypeName         this.#in1 = in1         this.#in2 = in2         this.#func = func         this.#out = this.#func(this.in1, this.in2)         // this.#lastOut = this.#out     }     updateIn1(flag){         this.#in1 = flag         this.#updateOut()     }     updateIn2(flag){         this.#in2 = flag         this.#updateOut()     }     getOut(){         return this.#out;     }     updateBothIn(in1 = false, in2 = false){         this.#in1 = in1         this.#in2 = in2         this.#updateOut()     }     setOutReceiver(outReceiver, inName){         this.#outReceiver = outReceiver         this.#outReceiverInName = inName     }     #updateOut(){         this.#lastOut = this.#out         this.#out = this.#func(this.#in1, this.#in2)         if(this.#out != this.#lastOut){             this.#send(this.#out)         }     }     #send(flag){         if(this.#outReceiver){             this.#outReceiver.receive(this.#outReceiverInName, flag)         }     }     receive(inName, flag){         if(inName == "in1"){             this.updateIn1(flag)         }else if(inName == "in2"){             this.updateIn2(flag)         }     }     toString(){         return "{gateTypeName} id: {id}, in1: {in1}, in2: {in2}, out:{out}"             .replace("{gateTypeName}", this.#gateTypeName)             .replace("{id}", this.#id)             .replace("{in1}", this.#in1)             .replace("{in2}", this.#in2)             .replace("{out}", this.#out)     } } //与门 class AndGate extends DoubleInGate{     constructor(id, in1 = false, in2 = false){         super(id, "AndGate", in1, in2, (i1, i2) => i1 && i2)     } } //或门 class OrGate extends DoubleInGate{     constructor(id, in1 = false, in2 = false){         super(id, "OrGate", in1, in2, (i1, i2) => i1 || i2)     } } //异或门 class XorGate extends DoubleInGate{     constructor(id, in1 = false, in2 = false){         //^在js按位异或, 而在java中不是         super(id, "XorGate", in1, in2, (i1, i2) => (i1 || i2) && !(i1 && i2))      } } class SingleInGate{     #id     #in     #out     #lastOut     #func     #outReceiver     #outReceiverInName     constructor(id, in_, func){         this.#id = id         this.#in = in_         this.#func = func         this.#out = this.#func(this.#in)         // this.#lastOut = this.#out     }     updateIn(flag){         this.#in = flag         this.#updateOut()     }     getOut(){         return this.#out     }     //注册输出端口接收者,(类观察者模式)     setOutReceiver(outReceiver, inName){         this.#outReceiver = outReceiver         this.#outReceiverInName = inName     }     #updateOut(){         this.#lastOut = this.#out         this.#out = this.#func(this.#in)         if(this.#out != this.#lastOut){             this.#send(this.#out)         }     }     #send(flag){         if(this.#outReceiver){             this.#outReceiver.receive(this.#outReceiverInName, flag)         }         }     receive(inName, flag){         if(inName == "in"){ //TODO 或许有更灵活的写法             this.updateIn(flag)         }     } } class NullGate extends SingleInGate{     constructor(id, in_= false){         super(id, in_, a=>a)     } } class NotGate extends SingleInGate{     constructor(id, in_= false){         super(id, in_, a=>!a)     } } class Adder{     #id     #inA     #inB     #outS     #outC     #lastOutS     #lastOutC     #outSReceiver     #outSReceiverInName     #outCReceiver     #outCReceiverInName     constructor(id, inA=false, inB=false, outS, outC){         this.#id = id         this.#inA = inA         this.#inB = inB         this.#outS = outS         this.#outC = outC     }     updateInA(flag, func){         this.#inA = flag         this.updateOutSAndOutC(func)     }     updateInB(flag, func){         this.#inB = flag         this.updateOutSAndOutC(func)     }     updateBothIn(inA, inB, func){         this.#inA = inA         this.#inB = inB         this.updateOutSAndOutC(func)     }     getOutS(){         return this.#outS     }     getOutC(){         return this.#outC     }     #updateOutS(flag){         this.#lastOutS = this.#outS         this.#outS = flag         if(this.#outS != this.#lastOutS){             this.#sendOutS(this.#outS)         }     }     #updateOutC(flag){         this.#lastOutC = this.#outC         this.#outC = flag         if(this.#outC != this.#lastOutC){             this.#sendOutC(this.#outC)         }     }     updateOutSAndOutC(func){         if(func){             var results = func()             this.#updateOutS(results[0])             this.#updateOutC(results[1])         }     }     setOutSReceiver(outSReceiver, inName){         this.#outSReceiver = outSReceiver         this.#outSReceiverInName = inName     }     setOutCReceiver(outCReceiver, inName){         this.#outCReceiver = outCReceiver         this.#outCReceiverInName = inName     }     receive(inName, flag){         if(inName == "inA"){             this.updateInA(flag)         }else if(inName == "inB"){             this.updateInB(flag)         }     }     #sendOutS(flag){         if(this.#outSReceiver){             this.#outSReceiver.receive(this.#outSReceiverInName, flag)         }     }     #sendOutC(flag){         if(this.#outCReceiver){             this.#outCReceiver.receive(this.#outCReceiverInName, flag)         }     } } class HalfAdder extends Adder{     #xorGate     #andGate     constructor(id, inA=false, inB=false){         var xorGate = new XorGate(undefined, inA, inB);         var andGate = new AndGate(undefined, inA, inB);         super(id, inA, inB, xorGate.getOut(), andGate.getOut())         this.#xorGate = xorGate         this.#andGate = andGate      }     #returnOutArray(){         return [this.#xorGate.getOut(), this.#andGate.getOut()]     }     updateInA(flag){         super.updateInA(flag, ()=>{             this.#xorGate.updateIn1(flag)             this.#andGate.updateIn1(flag)             return this.#returnOutArray()         })     }     updateInB(flag){         super.updateInB(flag, ()=>{             this.#xorGate.updateIn2(flag)             this.#andGate.updateIn2(flag)             return this.#returnOutArray()         })     }     updateBothIn(inA, inB){         super.updateBothIn(inA, inB, ()=>{             this.#xorGate.updateBothIn(inA, inB)             this.#andGate.updateBothIn(inA, inB)             return this.#returnOutArray()         })     } } class FullAdder extends Adder{     #inC     #halfAdder1     #halfAdder2     #orGate     constructor(id, inA = false, inB = false, inC = false){         var halfAdder1 = new HalfAdder(undefined, inA, inB)         var halfAdder2 = new HalfAdder(undefined, inC, halfAdder1.getOutS())         var orGate = new OrGate(undefined, halfAdder1.getOutC(), halfAdder2.getOutC())         super(id, inA, inB, halfAdder2.getOutS(), orGate.getOut())         this.#inC = inC         this.#halfAdder1 = halfAdder1         this.#halfAdder2 = halfAdder2         this.#orGate = orGate         this.#halfAdder1.setOutSReceiver(halfAdder2, "inB")         this.#halfAdder1.setOutCReceiver(orGate, "in1")         this.#halfAdder2.setOutCReceiver(orGate, "in2")     }     #returnOutArray(){         return [this.#halfAdder2.getOutS(), this.#orGate.getOut()]     }     updateInA(flag){         super.updateInA(flag, ()=>{             this.#halfAdder1.updateInA(flag)             return this.#returnOutArray()         })     }     updateInB(flag){         super.updateInB(flag, ()=>{             this.#halfAdder1.updateInB(flag)             return this.#returnOutArray()         })     }     updateInC(flag){         this.#inC = flag         this.#halfAdder2.updateInA(flag)         this.updateOutSAndOutC(()=>{             return this.#returnOutArray()         })     }     updateBothIn(inA, inB){         super.updateBothIn(inA, inB, ()=>{             this.#halfAdder1.updateBothIn(inA, inB)             return this.#returnOutArray()         })     }     updateThreeIn(inA, inB, inC){         super.updateBothIn(inA, inB)         this.#inC = inC         this.#halfAdder1.updateBothIn(inA, inB)         this.#halfAdder2.updateBothIn(inC, this.#halfAdder1.getOutS())         this.#orGate.updateBothIn(this.#halfAdder1.getOutC(), this.#halfAdder2.getOutC())         this.updateOutSAndOutC(()=>{             return this.#returnOutArray()         })     }     receive(inName, flag){         super.receive(inName, flag)         if(inName == "inC"){             this.updateInC(flag)         }     } } class EightBitBinaryAdder{     #inC     #outC     #lastOutC     #inA     #inB     #outS     #fullAdders     #fullAdderNum     #outCReceiver     #outCReceiverInName     #outCInOutSFlag     constructor(outCInOutSFlag = false){         this.#outCInOutSFlag = outCInOutSFlag         this.#inC = false         this.#fullAdderNum = 8         this.#fullAdders = []         this.#inA = []         this.#inB = []         for(var i = 0; i < this.#fullAdderNum; i++){             this.#inA.push(false)             this.#inB.push(false)         }         //新键8个全加器         for(var i = 0; i < this.#fullAdderNum; i++){             this.#fullAdders.push(new FullAdder("f" + i))             if(i != 0){                 this.#fullAdders[i - 1].setOutCReceiver(this.#fullAdders[i], "inC")             }         }         this.updateOut()     }     updateBothIn(arrayA, arrayB){         // this.#inC = inC         this.#inA = arrayA         this.#inB = arrayB         for(var i = 0; i < this.#fullAdderNum; i++){             if(i == 0){                 this.#fullAdders[i].updateInC(this.#inC)             }             this.#fullAdders[i].updateBothIn(arrayA[i], arrayB[i])         }         this.updateOut()     }     //输出默认值     updateOut(){         this.#outS = []         for(var i = 0; i < this.#fullAdderNum; i++){             this.#outS.push(this.#fullAdders[i].getOutS())             if(i == this.#fullAdderNum - 1){                 this.#lastOutC = this.#outC                 this.#outC = this.#fullAdders[i].getOutC()                 if(this.#lastOutC != this.#outC)                     this.#sendOutC(this.#outC)                 if(this.#outCInOutSFlag)                     this.#outS.push(this.#outC)             }         }     }     updateInC(flag){         this.#inC = flag         this.updateBothIn(this.#inA, this.#inB, flag)     }     receive(inName, flag){         if(inName == "inC"){             this.updateInC(flag)         }     }     #sendOutC(flag){         if(this.#outCReceiver){             this.#outCReceiver.receive(this.#outCReceiverInName, flag)         }     }     setOutCReceiver(outCReceiver, inName){         this.#outCReceiver = outCReceiver         this.#outCReceiverInName = inName     }     getOut(){         return this.#outS     } } class SixteenBitBinaryAdder{     #inC     #outC     #lastOutC     #inA     #inB     #outS     #eightBitBinaryAdder1     #eightBitBinaryAdder2     #bitNum = 16     #outCReceiver     #outCReceiverInName     #outCInOutSFlag     constructor(outCInOutSFlag){         this.#outCInOutSFlag = outCInOutSFlag         this.#inC = false         this.#eightBitBinaryAdder1 = new EightBitBinaryAdder()         this.#eightBitBinaryAdder2 = new EightBitBinaryAdder()         this.#inA = []         this.#inB = []         for(var i = 0; i < this.#bitNum; i++){             this.#inA.push(false)             this.#inB.push(false)         }         this.#eightBitBinaryAdder1.setOutCReceiver(this.#eightBitBinaryAdder2, "inC")         this.updateOut()     }     updateBothIn(arrayA, arrayB){         this.#inA = arrayA         this.#inB = arrayB         this.#eightBitBinaryAdder1.updateBothIn(arrayA.slice(0, 8), arrayB.slice(0, 8))         this.#eightBitBinaryAdder2.updateBothIn(arrayA.slice(8), arrayB.slice(8))         this.updateOut()     }     updateOut(){         this.#outS = this.#eightBitBinaryAdder1.getOut().concat(this.#eightBitBinaryAdder2.getOut())         //发送send(OutC)     }     getOut(){         return this.#outS     }     //TODO     // updateInC(flag){     //     this.#inC = flag     //     this.updateBothIn(this.#inA, this.#inB, flag)     // }     // receive(inName, flag){     //     if(inName == "inC"){     //         this.updateInC(flag)     //     }     // }     #sendOutC(flag){         if(this.#outCReceiver){             this.#outCReceiver.receive(this.#outCReceiverInName, flag)         }     }     setOutCReceiver(outCReceiver, inName){         this.#outCReceiver = outCReceiver         this.#outCReceiverInName = inName     } }

运行验证代码testModel.js
验证通过判据:后台没有打印输出异常。

<!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <meta http-equiv="X-UA-Compatible" content="IE=edge">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <title>Test</title>     <script src="../js/test/TestUtils.js"></script>     <script src="../js/model.js"></script>     <script src="../js/utils.js"></script> </head> <body>     <script>         var g1 = new NullGate("g1")         var g2 = new NullGate("g2")         var g3 = new NullGate("g3")         var g4 = new NullGate("g4")         var g5 = new NullGate("g5")         var g6 = new NullGate("g6")         g1.setOutReceiver(g2, "in")         g2.setOutReceiver(g3, "in")         g3.setOutReceiver(g4, "in")         g4.setOutReceiver(g5, "in")         g5.setOutReceiver(g6, "in")         g1.updateIn(true)         assertTrue(g6.getOut())     </script>     <script>         //与门         var andGate = new AndGate("a01")         assertFalse(andGate.getOut())         andGate.updateIn1(true)         assertFalse(andGate.getOut())         andGate.updateIn2(true)         assertTrue(andGate.getOut())         //或门         var orGate = new OrGate("o01")         assertFalse(orGate.getOut())         orGate.updateIn1(true)         assertTrue(orGate.getOut())         orGate.updateIn2(true)         assertTrue(orGate.getOut())         //异或门         var xorGate = new XorGate("x01")         assertFalse(xorGate.getOut())         xorGate.updateIn1(true)         assertTrue(xorGate.getOut())         xorGate.updateIn2(true)         assertFalse(xorGate.getOut())         xorGate.updateBothIn(false, true)         assertTrue(xorGate.getOut())     </script>     <script>         //半加器         var ha = new HalfAdder("h01")         assertFalse(ha.getOutS())         assertFalse(ha.getOutC())         ha.updateInB(true)         assertTrue(ha.getOutS())         assertFalse(ha.getOutC())         ha.updateInA(true)         assertFalse(ha.getOutS())         assertTrue(ha.getOutC())         ha.updateBothIn(true, false)         assertTrue(ha.getOutS())         assertFalse(ha.getOutC())     </script>     <script>         //全加器         var fa = new FullAdder("fa01")         assertFalse(fa.getOutC())         assertFalse(fa.getOutS())         function test(inA, inB, inC, expectedS, expectedC){             fa.updateThreeIn(inA, inB, inC)             if(expectedS)                 assertTrue(fa.getOutS())             else                 assertFalse(fa.getOutS())             if(expectedC)                 assertTrue(fa.getOutC())             else                 assertFalse(fa.getOutC())         }         test(false, false, false, false, false)         test(false, true, false, true, false)         test(true, false, false, true, false)         test(true, true, false, false, true)         test(false, false, true, true, false)         test(false, true, true, false, true)         test(true, false, true, false, true)         test(true, true, true, true, true)     </script>     <script>         for(var i = 0 ; i < 256; i++){             assertIntEquals(i, lowEightBitArray2Int(int2LowEightBitArray(i)))         }     </script>     <script>         var ebba = new EightBitBinaryAdder(true)         for(var i = 0; i < 256; i++){             for(var j = 0; j < 256; j++){i                 ebba.updateBothIn(int2LowEightBitArray(i), int2LowEightBitArray(j))                 assertIntEquals(i + j, lowNineBitArray2Int(ebba.getOut()))             }         }     </script>     <script>         for(var i = -128; i <= 127; i++){             assertIntEquals(i, eightBitArray2Int(int2EightBitArray(i)))         }     </script>     <script>         var ebba = new EightBitBinaryAdder()         for(var i = -64; i < 64; i++){             for(var j = -64; j < 64; j++){                 ebba.updateBothIn(int2EightBitArray(i), int2EightBitArray(j))                 assertIntEquals(i + j, eightBitArray2Int(ebba.getOut()))             }         }     </script>     <script>         for(var i = -(1<<15); i <= (1<<15) - 1; i++){             assertIntEquals(i, sixteentBitArray2Int(int2SixteenBitArray(i)))         }     </script>     <script>         var sbba = new SixteenBitBinaryAdder()         sbba.updateBothIn(int2SixteenBitArray(1156), int2SixteenBitArray(9999))         assertIntEquals(9999 + 1156, sixteentBitArray2Int(sbba.getOut()))         //‭16384‬ * ‭16384‬ = 268435456 如果这样算会十分耗时         // for(var i = -(1<<14); i < (1<<14); i++){         //     for(var j = -(1<<14); j < (1<<14); j++){         //         sbba.updateBothIn(int2SixteenBitArray(i), int2SixteenBitArray(j))         //         assertIntEquals(i + j, sixteentBitArray2Int(sbba.getOut()))         //     }         // }         for(var i = -100; i < 100; i++){             for(var j = -100; j < 100; j++){                 sbba.updateBothIn(int2SixteenBitArray(i), int2SixteenBitArray(j))                 assertIntEquals(i + j, sixteentBitArray2Int(sbba.getOut()))             }         }     </script> </body> </html>



加法器 js

需要 登录 后方可回复, 如果你还没有账号请 注册新账号