mirror of
https://github.com/trekhleb/javascript-algorithms.git
synced 2025-07-08 02:14:56 +08:00
Perform multiplication of any two integers positive or negative through bit manipulations (#201)
This commit is contained in:
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
#### Get Bit
|
#### Get Bit
|
||||||
|
|
||||||
This method shifts the relevant bit to the zeroth position.
|
This method shifts the relevant bit to the zeroth position.
|
||||||
Then we perform `AND` operation with one which has bit
|
Then we perform `AND` operation with one which has bit
|
||||||
pattern like `0001`. This clears all bits from the original
|
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`.
|
the result is `1`, otherwise the result is `0`.
|
||||||
|
|
||||||
> See [getBit.js](getBit.js) for further details.
|
> 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
|
This method shifts `1` over by `bitPosition` bits, creating a
|
||||||
value that looks like `00100`. Than it inverts this mask to get
|
value that looks like `00100`. Than it inverts this mask to get
|
||||||
the number that looks like `11011`. Then `AND` operation is
|
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.
|
unsets the bit.
|
||||||
|
|
||||||
> See [clearBit.js](clearBit.js) for further details.
|
> 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.
|
> 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
|
#### Multiply By Two
|
||||||
|
|
||||||
This method shifts original number by one bit to the left.
|
This method shifts original number by one bit to the left.
|
||||||
Thus all binary number components (powers of two) are being
|
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.
|
multiplied by two.
|
||||||
|
|
||||||
```
|
```
|
||||||
Before the shift
|
Before the shift
|
||||||
Number: 0b0101 = 5
|
Number: 0b0101 = 5
|
||||||
Powers of two: 0 + 2^2 + 0 + 2^0
|
Powers of two: 0 + 2^2 + 0 + 2^0
|
||||||
|
|
||||||
After the shift
|
After the shift
|
||||||
Number: 0b1010 = 10
|
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.
|
> 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.
|
This method shifts original number by one bit to the right.
|
||||||
Thus all binary number components (powers of two) are being
|
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.
|
divided by two without remainder.
|
||||||
|
|
||||||
```
|
```
|
||||||
Before the shift
|
Before the shift
|
||||||
Number: 0b0101 = 5
|
Number: 0b0101 = 5
|
||||||
Powers of two: 0 + 2^2 + 0 + 2^0
|
Powers of two: 0 + 2^2 + 0 + 2^0
|
||||||
|
|
||||||
After the shift
|
After the shift
|
||||||
Number: 0b0010 = 2
|
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.
|
> 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
|
0001 1
|
||||||
0010 2
|
0010 2
|
||||||
0011 3
|
0011 3
|
||||||
```
|
```
|
||||||
|
|
||||||
> See [switchSign.js](switchSign.js) for further details.
|
> 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 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".
|
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
|
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`).
|
by `4` bits (`x << 4`).
|
||||||
|
|
||||||
> See [multiplyUnsigned.js](multiplyUnsigned.js) for further details.
|
> 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
|
#### 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
|
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`
|
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).
|
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();
|
||||||
|
}
|
Reference in New Issue
Block a user