mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-12-25 22:46:20 +08:00
Perform multiplication of any two integers positive or negative through bit manipulations (#201)
This commit is contained in:
parent
1a62078f26
commit
bc8943dee2
@ -2,10 +2,10 @@
|
||||
|
||||
#### Get Bit
|
||||
|
||||
This method shifts the relevant bit to the zeroth position.
|
||||
Then we perform `AND` operation with one which has bit
|
||||
This method shifts the relevant bit to the zeroth position.
|
||||
Then we perform `AND` operation with one which has bit
|
||||
pattern like `0001`. This clears all bits from the original
|
||||
number except the relevant one. If the relevant bit is one,
|
||||
number except the relevant one. If the relevant bit is one,
|
||||
the result is `1`, otherwise the result is `0`.
|
||||
|
||||
> See [getBit.js](getBit.js) for further details.
|
||||
@ -24,7 +24,7 @@ other bits of the number.
|
||||
This method shifts `1` over by `bitPosition` bits, creating a
|
||||
value that looks like `00100`. Than it inverts this mask to get
|
||||
the number that looks like `11011`. Then `AND` operation is
|
||||
being applied to both the number and the mask. That operation
|
||||
being applied to both the number and the mask. That operation
|
||||
unsets the bit.
|
||||
|
||||
> See [clearBit.js](clearBit.js) for further details.
|
||||
@ -35,21 +35,35 @@ This method is a combination of "Clear Bit" and "Set Bit" methods.
|
||||
|
||||
> See [updateBit.js](updateBit.js) for further details.
|
||||
|
||||
#### isEven
|
||||
|
||||
This method determines if the number provided is even.
|
||||
|
||||
```
|
||||
Number: 5
|
||||
isEven: false
|
||||
|
||||
Number: 4
|
||||
isEven: true
|
||||
```
|
||||
|
||||
> See [isEven.js](isEven.js) for further details.
|
||||
|
||||
#### Multiply By Two
|
||||
|
||||
This method shifts original number by one bit to the left.
|
||||
Thus all binary number components (powers of two) are being
|
||||
multiplying by two and thus the number itself is being
|
||||
multiplying by two and thus the number itself is being
|
||||
multiplied by two.
|
||||
|
||||
```
|
||||
Before the shift
|
||||
Number: 0b0101 = 5
|
||||
Powers of two: 0 + 2^2 + 0 + 2^0
|
||||
Powers of two: 0 + 2^2 + 0 + 2^0
|
||||
|
||||
After the shift
|
||||
Number: 0b1010 = 10
|
||||
Powers of two: 2^3 + 0 + 2^1 + 0
|
||||
Powers of two: 2^3 + 0 + 2^1 + 0
|
||||
```
|
||||
|
||||
> See [multiplyByTwo.js](multiplyByTwo.js) for further details.
|
||||
@ -58,17 +72,17 @@ Powers of two: 2^3 + 0 + 2^1 + 0
|
||||
|
||||
This method shifts original number by one bit to the right.
|
||||
Thus all binary number components (powers of two) are being
|
||||
divided by two and thus the number itself is being
|
||||
divided by two and thus the number itself is being
|
||||
divided by two without remainder.
|
||||
|
||||
```
|
||||
Before the shift
|
||||
Number: 0b0101 = 5
|
||||
Powers of two: 0 + 2^2 + 0 + 2^0
|
||||
Powers of two: 0 + 2^2 + 0 + 2^0
|
||||
|
||||
After the shift
|
||||
Number: 0b0010 = 2
|
||||
Powers of two: 0 + 0 + 2^1 + 0
|
||||
Powers of two: 0 + 0 + 2^1 + 0
|
||||
```
|
||||
|
||||
> 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.
|
||||
0001 1
|
||||
0010 2
|
||||
0011 3
|
||||
```
|
||||
```
|
||||
|
||||
> See [switchSign.js](switchSign.js) for further details.
|
||||
|
||||
#### Multiply Two Numbers
|
||||
#### Multiply Two Signed Numbers
|
||||
|
||||
This method multiplies two signed integer numbers using bitwise operators.
|
||||
This method is based on the following :
|
||||
|
||||
```text
|
||||
a * b can be written in the below formats
|
||||
0 if a is zero or b is zero or both a and b are zeroes
|
||||
2a * (b/2) if b is even
|
||||
2a * (b - 1)/2 + a if b is odd and positive
|
||||
2a * (b + 1)/2 - a if b is odd and negative
|
||||
```
|
||||
|
||||
The advantage of this approach is that in each recursive step one of the operands reduces to half its original value.
|
||||
Hence, the run time complexity is O(log b) where b is the operand that reduces to half on each recursive step.
|
||||
|
||||
> See [multiply.js](multiply.js) for further details.
|
||||
|
||||
#### Multiply Two Unsigned Numbers
|
||||
|
||||
This method multiplies two integer numbers using bitwise operators.
|
||||
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:
|
||||
x * 19 = x * 2^4 + x * 2^1 + x * 2^0
|
||||
```
|
||||
|
||||
Now we need to remember that `x * 2^4` is equivalent of shifting `x` left
|
||||
Now we need to remember that `x * 2^4` is equivalent of shifting `x` left
|
||||
by `4` bits (`x << 4`).
|
||||
|
||||
> See [multiplyUnsigned.js](multiplyUnsigned.js) for further details.
|
||||
@ -158,7 +190,7 @@ When we shift 1 four times it will become bigger than 5.
|
||||
|
||||
#### Is Power of Two
|
||||
|
||||
This method checks if a number provided is power of two. It uses the following
|
||||
This method checks if a number provided is power of two. It uses the following
|
||||
property. Let's say that `powerNumber` is a number that has been formed as a power
|
||||
of two (i.e. 2, 4, 8, 16 etc.). Then if we'll do `&` operation between `powerNumber`
|
||||
and `powerNumber - 1` it will return `0` (in case if number is power of two).
|
||||
|
11
src/algorithms/math/bits/__test__/isEven.test.js
Normal file
11
src/algorithms/math/bits/__test__/isEven.test.js
Normal file
@ -0,0 +1,11 @@
|
||||
import isEven from '../isEven';
|
||||
|
||||
describe('isEven', () => {
|
||||
it('should detect if a number is even', () => {
|
||||
expect(isEven(0)).toBe(true);
|
||||
expect(isEven(2)).toBe(true);
|
||||
expect(isEven(-2)).toBe(true);
|
||||
expect(isEven(1)).toBe(false);
|
||||
expect(isEven(-1)).toBe(false);
|
||||
});
|
||||
});
|
16
src/algorithms/math/bits/__test__/multiply.test.js
Normal file
16
src/algorithms/math/bits/__test__/multiply.test.js
Normal file
@ -0,0 +1,16 @@
|
||||
import multiply from '../multiply';
|
||||
|
||||
describe('multiply', () => {
|
||||
it('should multiply two numbers', () => {
|
||||
expect(multiply(0, 0)).toBe(0);
|
||||
expect(multiply(2, 0)).toBe(0);
|
||||
expect(multiply(0, 2)).toBe(0);
|
||||
expect(multiply(1, 2)).toBe(2);
|
||||
expect(multiply(2, 1)).toBe(2);
|
||||
expect(multiply(6, 6)).toBe(36);
|
||||
expect(multiply(-2, 4)).toBe(-8);
|
||||
expect(multiply(4, -2)).toBe(-8);
|
||||
expect(multiply(-4, -4)).toBe(16);
|
||||
expect(multiply(4, -5)).toBe(-20);
|
||||
});
|
||||
});
|
7
src/algorithms/math/bits/isEven.js
Normal file
7
src/algorithms/math/bits/isEven.js
Normal file
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* @param {number} number
|
||||
* @return bool
|
||||
*/
|
||||
export default function isEven(number) {
|
||||
return (number & 1) === 0;
|
||||
}
|
29
src/algorithms/math/bits/multiply.js
Normal file
29
src/algorithms/math/bits/multiply.js
Normal file
@ -0,0 +1,29 @@
|
||||
import divideByTwo from './divideByTwo';
|
||||
import isEven from './isEven';
|
||||
import multiplyByTwo from './multiplyByTwo';
|
||||
|
||||
/**
|
||||
* FUNCTION DEFINITION
|
||||
* multiply(a, b) = 0 if a is zero or b is zero or if both a and b are zeros
|
||||
* multiply(a, b) = multiply(2a, b/2) if b is even
|
||||
* multiply(a, b) = multiply(2a, (b-1)/2) + a if b is odd and b is positive
|
||||
* multiply(a, b) = multiply(2a, (b+1)/2) - a if b is odd and b is negative
|
||||
*
|
||||
* COMPLEXITY
|
||||
* O(log b)
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @return {number} a * b
|
||||
*/
|
||||
export default function multiply(a, b) {
|
||||
if (b === 0 || a === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const multiplyByOddPositive = () => multiply(multiplyByTwo(a), divideByTwo(b - 1)) + a;
|
||||
const multiplyByOddNegative = () => multiply(multiplyByTwo(a), divideByTwo(b + 1)) - a;
|
||||
const multiplyByEven = () => multiply(multiplyByTwo(a), divideByTwo(b));
|
||||
const multiplyByOdd = () => (b > 0 ? multiplyByOddPositive() : multiplyByOddNegative());
|
||||
|
||||
return isEven(b) ? multiplyByEven() : multiplyByOdd();
|
||||
}
|
Loading…
Reference in New Issue
Block a user