Skip to content

Commit bc8943d

Browse files
adityahirantrekhleb
authored andcommitted
Perform multiplication of any two integers positive or negative through bit manipulations (trekhleb#201)
1 parent 1a62078 commit bc8943d

File tree

5 files changed

+109
-14
lines changed

5 files changed

+109
-14
lines changed

Diff for: src/algorithms/math/bits/README.md

+46-14
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
#### Get Bit
44

5-
This method shifts the relevant bit to the zeroth position.
6-
Then we perform `AND` operation with one which has bit
5+
This method shifts the relevant bit to the zeroth position.
6+
Then we perform `AND` operation with one which has bit
77
pattern like `0001`. This clears all bits from the original
8-
number except the relevant one. If the relevant bit is one,
8+
number except the relevant one. If the relevant bit is one,
99
the result is `1`, otherwise the result is `0`.
1010

1111
> See [getBit.js](getBit.js) for further details.
@@ -24,7 +24,7 @@ other bits of the number.
2424
This method shifts `1` over by `bitPosition` bits, creating a
2525
value that looks like `00100`. Than it inverts this mask to get
2626
the number that looks like `11011`. Then `AND` operation is
27-
being applied to both the number and the mask. That operation
27+
being applied to both the number and the mask. That operation
2828
unsets the bit.
2929

3030
> See [clearBit.js](clearBit.js) for further details.
@@ -35,21 +35,35 @@ This method is a combination of "Clear Bit" and "Set Bit" methods.
3535

3636
> See [updateBit.js](updateBit.js) for further details.
3737
38+
#### isEven
39+
40+
This method determines if the number provided is even.
41+
42+
```
43+
Number: 5
44+
isEven: false
45+
46+
Number: 4
47+
isEven: true
48+
```
49+
50+
> See [isEven.js](isEven.js) for further details.
51+
3852
#### Multiply By Two
3953

4054
This method shifts original number by one bit to the left.
4155
Thus all binary number components (powers of two) are being
42-
multiplying by two and thus the number itself is being
56+
multiplying by two and thus the number itself is being
4357
multiplied by two.
4458

4559
```
4660
Before the shift
4761
Number: 0b0101 = 5
48-
Powers of two: 0 + 2^2 + 0 + 2^0
62+
Powers of two: 0 + 2^2 + 0 + 2^0
4963
5064
After the shift
5165
Number: 0b1010 = 10
52-
Powers of two: 2^3 + 0 + 2^1 + 0
66+
Powers of two: 2^3 + 0 + 2^1 + 0
5367
```
5468

5569
> See [multiplyByTwo.js](multiplyByTwo.js) for further details.
@@ -58,17 +72,17 @@ Powers of two: 2^3 + 0 + 2^1 + 0
5872

5973
This method shifts original number by one bit to the right.
6074
Thus all binary number components (powers of two) are being
61-
divided by two and thus the number itself is being
75+
divided by two and thus the number itself is being
6276
divided by two without remainder.
6377

6478
```
6579
Before the shift
6680
Number: 0b0101 = 5
67-
Powers of two: 0 + 2^2 + 0 + 2^0
81+
Powers of two: 0 + 2^2 + 0 + 2^0
6882
6983
After the shift
7084
Number: 0b0010 = 2
71-
Powers of two: 0 + 0 + 2^1 + 0
85+
Powers of two: 0 + 0 + 2^1 + 0
7286
```
7387

7488
> See [divideByTwo.js](divideByTwo.js) for further details.
@@ -87,11 +101,29 @@ inverting all of the bits of the number and adding 1 to it.
87101
0001 1
88102
0010 2
89103
0011 3
90-
```
104+
```
91105

92106
> See [switchSign.js](switchSign.js) for further details.
93107
94-
#### Multiply Two Numbers
108+
#### Multiply Two Signed Numbers
109+
110+
This method multiplies two signed integer numbers using bitwise operators.
111+
This method is based on the following :
112+
113+
```text
114+
a * b can be written in the below formats
115+
0 if a is zero or b is zero or both a and b are zeroes
116+
2a * (b/2) if b is even
117+
2a * (b - 1)/2 + a if b is odd and positive
118+
2a * (b + 1)/2 - a if b is odd and negative
119+
```
120+
121+
The advantage of this approach is that in each recursive step one of the operands reduces to half its original value.
122+
Hence, the run time complexity is O(log b) where b is the operand that reduces to half on each recursive step.
123+
124+
> See [multiply.js](multiply.js) for further details.
125+
126+
#### Multiply Two Unsigned Numbers
95127

96128
This method multiplies two integer numbers using bitwise operators.
97129
This method is based on that "Every number can be denoted as the sum of powers of 2".
@@ -111,7 +143,7 @@ Then multiplying number `x` by `19` is equivalent of:
111143
x * 19 = x * 2^4 + x * 2^1 + x * 2^0
112144
```
113145

114-
Now we need to remember that `x * 2^4` is equivalent of shifting `x` left
146+
Now we need to remember that `x * 2^4` is equivalent of shifting `x` left
115147
by `4` bits (`x << 4`).
116148

117149
> See [multiplyUnsigned.js](multiplyUnsigned.js) for further details.
@@ -158,7 +190,7 @@ When we shift 1 four times it will become bigger than 5.
158190
159191
#### Is Power of Two
160192

161-
This method checks if a number provided is power of two. It uses the following
193+
This method checks if a number provided is power of two. It uses the following
162194
property. Let's say that `powerNumber` is a number that has been formed as a power
163195
of two (i.e. 2, 4, 8, 16 etc.). Then if we'll do `&` operation between `powerNumber`
164196
and `powerNumber - 1` it will return `0` (in case if number is power of two).

Diff for: src/algorithms/math/bits/__test__/isEven.test.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import isEven from '../isEven';
2+
3+
describe('isEven', () => {
4+
it('should detect if a number is even', () => {
5+
expect(isEven(0)).toBe(true);
6+
expect(isEven(2)).toBe(true);
7+
expect(isEven(-2)).toBe(true);
8+
expect(isEven(1)).toBe(false);
9+
expect(isEven(-1)).toBe(false);
10+
});
11+
});

Diff for: src/algorithms/math/bits/__test__/multiply.test.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import multiply from '../multiply';
2+
3+
describe('multiply', () => {
4+
it('should multiply two numbers', () => {
5+
expect(multiply(0, 0)).toBe(0);
6+
expect(multiply(2, 0)).toBe(0);
7+
expect(multiply(0, 2)).toBe(0);
8+
expect(multiply(1, 2)).toBe(2);
9+
expect(multiply(2, 1)).toBe(2);
10+
expect(multiply(6, 6)).toBe(36);
11+
expect(multiply(-2, 4)).toBe(-8);
12+
expect(multiply(4, -2)).toBe(-8);
13+
expect(multiply(-4, -4)).toBe(16);
14+
expect(multiply(4, -5)).toBe(-20);
15+
});
16+
});

Diff for: src/algorithms/math/bits/isEven.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* @param {number} number
3+
* @return bool
4+
*/
5+
export default function isEven(number) {
6+
return (number & 1) === 0;
7+
}

Diff for: src/algorithms/math/bits/multiply.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import divideByTwo from './divideByTwo';
2+
import isEven from './isEven';
3+
import multiplyByTwo from './multiplyByTwo';
4+
5+
/**
6+
* FUNCTION DEFINITION
7+
* multiply(a, b) = 0 if a is zero or b is zero or if both a and b are zeros
8+
* multiply(a, b) = multiply(2a, b/2) if b is even
9+
* multiply(a, b) = multiply(2a, (b-1)/2) + a if b is odd and b is positive
10+
* multiply(a, b) = multiply(2a, (b+1)/2) - a if b is odd and b is negative
11+
*
12+
* COMPLEXITY
13+
* O(log b)
14+
* @param {number} a
15+
* @param {number} b
16+
* @return {number} a * b
17+
*/
18+
export default function multiply(a, b) {
19+
if (b === 0 || a === 0) {
20+
return 0;
21+
}
22+
23+
const multiplyByOddPositive = () => multiply(multiplyByTwo(a), divideByTwo(b - 1)) + a;
24+
const multiplyByOddNegative = () => multiply(multiplyByTwo(a), divideByTwo(b + 1)) - a;
25+
const multiplyByEven = () => multiply(multiplyByTwo(a), divideByTwo(b));
26+
const multiplyByOdd = () => (b > 0 ? multiplyByOddPositive() : multiplyByOddNegative());
27+
28+
return isEven(b) ? multiplyByEven() : multiplyByOdd();
29+
}

0 commit comments

Comments
 (0)