From 2d3741529f263c3566e739cb9e5b234775505f33 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Tue, 2 Apr 2019 21:13:42 -0400 Subject: [PATCH 1/3] Add Full Adder algorithm (math/bits) --- src/algorithms/math/bits/README.md | 36 ++++++++++ .../math/bits/__test__/fullAdder.test.js | 18 +++++ src/algorithms/math/bits/fullAdder.js | 66 +++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 src/algorithms/math/bits/__test__/fullAdder.test.js create mode 100644 src/algorithms/math/bits/fullAdder.js diff --git a/src/algorithms/math/bits/README.md b/src/algorithms/math/bits/README.md index 2aa672a54b..4986c534c5 100644 --- a/src/algorithms/math/bits/README.md +++ b/src/algorithms/math/bits/README.md @@ -226,6 +226,42 @@ Number: 9 = (10 - 1) = 0b01001 > See [isPowerOfTwo.js](isPowerOfTwo.js) for further details. + +#### Full Adder + +This method adds up two integer numbers using bitwise operators. + +It implements [full adder](https://en.wikipedia.org/wiki/Adder_(electronics)) +electronics circut logic to sum two 32-bit integers in two's complement format. +It's using the boolean logic to cover all possible cases of adding input two bits, +with and without a "carry bit" from adding a previous register. + +Legend: +- `A`: Number `A` +- `B`: Number `B` +- `ai`: ith bit of number `A` +- `bi`: ith bit of number `B` +- `carryIn`: a bit carried in from the previous less-significant stage +- `carryOut`: a bit to carry to the next most-significant stage +- `bitSum`: The sum of `ai`, `bi`, and `carryIn` +- `resultBin`: The full result of adding current stage with all less-significant stages (in binary) +- `resultBin`: The full result of adding current stage with all less-significant stages (in decimal) +``` +A = 3: 011 +B = 6: 110 +┌──────┬────┬────┬─────────┬──────────┬─────────┬───────────┬───────────┐ +│ bit │ ai │ bi │ carryIn │ carryOut │ bitSum │ resultBin │ resultDec │ +├──────┼────┼────┼─────────┼──────────┼─────────┼───────────┼───────────┤ +│ 0 │ 1 │ 0 │ 0 │ 0 │ 1 │ 1 │ 1 │ +│ 1 │ 1 │ 1 │ 0 │ 1 │ 0 │ 01 │ 1 │ +│ 2 │ 0 │ 1 │ 1 │ 1 │ 0 │ 001 │ 1 │ +│ 3 │ 0 │ 0 │ 1 │ 0 │ 1 │ 1001 │ 9 │ +└──────┴────┴────┴─────────┴──────────┴─────────┴───────────┴───────────┘ +``` + +> See [fullAdder.js](fullAdder.js) for further details. +> See [Full Adder on YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc). + ## References - [Bit Manipulation on YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) diff --git a/src/algorithms/math/bits/__test__/fullAdder.test.js b/src/algorithms/math/bits/__test__/fullAdder.test.js new file mode 100644 index 0000000000..e21a07d96a --- /dev/null +++ b/src/algorithms/math/bits/__test__/fullAdder.test.js @@ -0,0 +1,18 @@ +import fullAdder from '../fullAdder'; + +describe('Full adder', () => { + it('should add up two numbers', () => { + expect(fullAdder(0, 0)).toBe(0); + expect(fullAdder(2, 0)).toBe(2); + expect(fullAdder(0, 2)).toBe(2); + expect(fullAdder(1, 2)).toBe(3); + expect(fullAdder(2, 1)).toBe(3); + expect(fullAdder(6, 6)).toBe(12); + expect(fullAdder(-2, 4)).toBe(2); + expect(fullAdder(4, -2)).toBe(2); + expect(fullAdder(-4, -4)).toBe(-8); + expect(fullAdder(4, -5)).toBe(-1); + expect(fullAdder(2, 121)).toBe(123); + expect(fullAdder(121, 2)).toBe(123); + }); +}); diff --git a/src/algorithms/math/bits/fullAdder.js b/src/algorithms/math/bits/fullAdder.js new file mode 100644 index 0000000000..920a10ddec --- /dev/null +++ b/src/algorithms/math/bits/fullAdder.js @@ -0,0 +1,66 @@ +import getBit from './getBit'; + +/** + * Add two numbers using only binary operators. + * + * This is an implementation of full adders logic circut. + * https://en.wikipedia.org/wiki/Adder_(electronics) + * Inspired by: https://www.youtube.com/watch?v=wvJc9CZcvBc + * + * Table(1) + * INPUT | OUT + * C A B C R + * ----- | --- | + * 0 0 0 | 0 0 | + * 0 0 1 | 0 1 | + * 0 1 0 | 0 1 | + * 0 1 1 | 1 0 | + * ----- | --- | + * 1 0 0 | 0 1 | + * 1 0 1 | 1 0 | + * 1 1 0 | 1 0 | + * 1 1 1 | 1 1 | + * ------------- + * + * Legend: + * First C = Carry in + * A = Number A + * B = Number B + * Second C = Carry out + * R = Result Bit + * + * + * @param {number} a + * @param {number} b + * @return {number} + */ +export default function fullAdder(a, b) { + let result = 0; + let carry = 0; + + // The operands of all bitwise operators are converted to signed + // 32-bit integers in two's complement format. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Signed_32-bit_integers + for (let i = 0; i < 32; i += 1) { + const ai = getBit(a, i); + const bi = getBit(b, i); + const carryIn = carry; + + // Calculate binary ai + bi without carry + const aiPlusBi = ai ^ bi; + // Calculate ith bit of the result by "adding" carryIn to ai + bi + // See table(1) row 1 - 4 for carry = 0 + // See table(1) row 2 - 8 for carry = 1 + const bitSum = aiPlusBi ^ carryIn; + + // Carry out a bit when at least one of these is true: + // 1) table(1) rows 6, 7: carryIn = 1 AND one of ai OR bi is 1 + // 2) table(1) rows 4, 8: Both ai AND bi are 1 + const carryOut = (aiPlusBi & carryIn) | (ai & bi); + carry = carryOut; + + // Set ith bit of the result to bitSum. + result |= bitSum << i; + } + return result; +} From 78607b78be085d520f4b0d89caa985ceb212f003 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Tue, 2 Apr 2019 22:02:20 -0400 Subject: [PATCH 2/3] Full adder: minor spelling fixes --- src/algorithms/math/bits/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/math/bits/README.md b/src/algorithms/math/bits/README.md index 4986c534c5..83c7d85742 100644 --- a/src/algorithms/math/bits/README.md +++ b/src/algorithms/math/bits/README.md @@ -233,8 +233,8 @@ This method adds up two integer numbers using bitwise operators. It implements [full adder](https://en.wikipedia.org/wiki/Adder_(electronics)) electronics circut logic to sum two 32-bit integers in two's complement format. -It's using the boolean logic to cover all possible cases of adding input two bits, -with and without a "carry bit" from adding a previous register. +It's using the boolean logic to cover all possible cases of adding two input bits: +with and without a "carry bit" from adding the previous less-significant stage. Legend: - `A`: Number `A` From 5b7b8197f56e4fe90470bf3670a0e1d7cba26d0f Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Wed, 3 Apr 2019 00:06:21 -0400 Subject: [PATCH 3/3] Full adder: even better comments --- src/algorithms/math/bits/fullAdder.js | 55 ++++++++++++++------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/algorithms/math/bits/fullAdder.js b/src/algorithms/math/bits/fullAdder.js index 920a10ddec..f97f4e5fed 100644 --- a/src/algorithms/math/bits/fullAdder.js +++ b/src/algorithms/math/bits/fullAdder.js @@ -8,26 +8,26 @@ import getBit from './getBit'; * Inspired by: https://www.youtube.com/watch?v=wvJc9CZcvBc * * Table(1) - * INPUT | OUT - * C A B C R - * ----- | --- | - * 0 0 0 | 0 0 | - * 0 0 1 | 0 1 | - * 0 1 0 | 0 1 | - * 0 1 1 | 1 0 | - * ----- | --- | - * 1 0 0 | 0 1 | - * 1 0 1 | 1 0 | - * 1 1 0 | 1 0 | - * 1 1 1 | 1 1 | - * ------------- + * INPUT | OUT + * C Ai Bi | C Si | Row + * -------- | -----| --- + * 0 0 0 | 0 0 | 1 + * 0 0 1 | 0 1 | 2 + * 0 1 0 | 0 1 | 3 + * 0 1 1 | 1 0 | 4 + * -------- | ---- | -- + * 1 0 0 | 0 1 | 5 + * 1 0 1 | 1 0 | 6 + * 1 1 0 | 1 0 | 7 + * 1 1 1 | 1 1 | 8 + * --------------------- * * Legend: - * First C = Carry in - * A = Number A - * B = Number B - * Second C = Carry out - * R = Result Bit + * INPUT C = Carry in, from the previous less-significant stage + * INPUT Ai = ith bit of Number A + * INPUT Bi = ith bit of Number B + * OUT C = Carry out to the next most-significant stage + * OUT Si = Bit Sum, ith least significant bit of the result * * * @param {number} a @@ -46,20 +46,23 @@ export default function fullAdder(a, b) { const bi = getBit(b, i); const carryIn = carry; - // Calculate binary ai + bi without carry + // Calculate binary Ai + Bi without carry (half adder) + // See Table(1) rows 1 - 4: Si = Ai ^ Bi const aiPlusBi = ai ^ bi; - // Calculate ith bit of the result by "adding" carryIn to ai + bi - // See table(1) row 1 - 4 for carry = 0 - // See table(1) row 2 - 8 for carry = 1 + + // Calculate ith bit of the result by adding the carry bit to Ai + Bi + // For Table(1) rows 5 - 8 carryIn = 1: Si = Ai ^ Bi ^ 1, flip the bit + // Fpr Table(1) rows 1 - 4 carryIn = 0: Si = Ai ^ Bi ^ 0, a no-op. const bitSum = aiPlusBi ^ carryIn; - // Carry out a bit when at least one of these is true: - // 1) table(1) rows 6, 7: carryIn = 1 AND one of ai OR bi is 1 - // 2) table(1) rows 4, 8: Both ai AND bi are 1 + // Carry out one to the next most-significant stage + // when at least one of these is true: + // 1) Table(1) rows 6, 7: one of Ai OR Bi is 1 AND carryIn = 1 + // 2) Table(1) rows 4, 8: Both Ai AND Bi are 1 const carryOut = (aiPlusBi & carryIn) | (ai & bi); carry = carryOut; - // Set ith bit of the result to bitSum. + // Set ith least significant bit of the result to bitSum. result |= bitSum << i; } return result;