Add isPowerOfTwo functions.

This commit is contained in:
Oleksii Trekhleb 2018-06-04 20:42:22 +03:00
parent beb8501aca
commit 74b93d36cb
6 changed files with 174 additions and 0 deletions

View File

@ -50,6 +50,7 @@ a set of rules that precisely define a sequence of operations.
* [Least Common Multiple](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/least-common-multiple) (LCM) * [Least Common Multiple](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/least-common-multiple) (LCM)
* [Integer Partition](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/integer-partition) * [Integer Partition](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/integer-partition)
* [Sieve of Eratosthenes](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/sieve-of-eratosthenes) - finding all prime numbers up to any given limit * [Sieve of Eratosthenes](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/sieve-of-eratosthenes) - finding all prime numbers up to any given limit
* [Is Power of Two](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/is-power-of-two) - check if the number is power of two (naive and bitwise algorithms)
* **Sets** * **Sets**
* [Cartesian Product](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/cartesian-product) - product of multiple sets * [Cartesian Product](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/cartesian-product) - product of multiple sets
* [Power Set](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/power-set) - all subsets of a set * [Power Set](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/power-set) - all subsets of a set

View File

@ -0,0 +1,52 @@
# Is a power of two
Given a positive integer, write a function to find if it is
a power of two or not.
**Naive solution**
In naive solution we just keep dividing the number by two
unless the number becomes `1` and every time we do so we
check that remainder after division is always `0`. Otherwise
the number can't be a power of two.
**Bitwise solution**
Powers of two in binary form always have just one bit.
The only exception is with a signed integer (e.g. an 8-bit
signed integer with a value of -128 looks like: `10000000`)
```
1: 0001
2: 0010
4: 0100
8: 1000
```
So after checking that the number is greater than zero,
we can use a bitwise hack to test that one and only one
bit is set.
```
number & (number - 1)
```
For example for number `8` that operations will look like:
```
1000
- 0001
----
0111
1000
& 0111
----
0000
```
## References
- [GeeksForGeeks](https://www.geeksforgeeks.org/program-to-find-whether-a-no-is-power-of-two/)
- [Bitwise Solution on Stanford](http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2)
- [Binary number subtraction on YouTube](https://www.youtube.com/watch?v=S9LJknZTyos&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=66)

View File

@ -0,0 +1,30 @@
import isPowerOfTwo from '../isPowerOfTwo';
describe('isPowerOfTwo', () => {
it('should throw an exception when trying to apply function to negative number', () => {
const isNegativePowerOfTwo = () => {
isPowerOfTwo(-1);
};
expect(isNegativePowerOfTwo).toThrowError();
});
it('should check if the number is made by multiplying twos', () => {
expect(isPowerOfTwo(0)).toBeFalsy();
expect(isPowerOfTwo(1)).toBeFalsy();
expect(isPowerOfTwo(2)).toBeTruthy();
expect(isPowerOfTwo(3)).toBeFalsy();
expect(isPowerOfTwo(4)).toBeTruthy();
expect(isPowerOfTwo(5)).toBeFalsy();
expect(isPowerOfTwo(6)).toBeFalsy();
expect(isPowerOfTwo(7)).toBeFalsy();
expect(isPowerOfTwo(8)).toBeTruthy();
expect(isPowerOfTwo(10)).toBeFalsy();
expect(isPowerOfTwo(12)).toBeFalsy();
expect(isPowerOfTwo(16)).toBeTruthy();
expect(isPowerOfTwo(31)).toBeFalsy();
expect(isPowerOfTwo(64)).toBeTruthy();
expect(isPowerOfTwo(1024)).toBeTruthy();
expect(isPowerOfTwo(1023)).toBeFalsy();
});
});

View File

@ -0,0 +1,30 @@
import isPowerOfTwoBitwise from '../isPowerOfTwoBitwise';
describe('isPowerOfTwoBitwise', () => {
it('should throw an exception when trying to apply function to negative number', () => {
const isNegativePowerOfTwo = () => {
isPowerOfTwoBitwise(-1);
};
expect(isNegativePowerOfTwo).toThrowError();
});
it('should check if the number is made by multiplying twos', () => {
expect(isPowerOfTwoBitwise(0)).toBeFalsy();
expect(isPowerOfTwoBitwise(1)).toBeFalsy();
expect(isPowerOfTwoBitwise(2)).toBeTruthy();
expect(isPowerOfTwoBitwise(3)).toBeFalsy();
expect(isPowerOfTwoBitwise(4)).toBeTruthy();
expect(isPowerOfTwoBitwise(5)).toBeFalsy();
expect(isPowerOfTwoBitwise(6)).toBeFalsy();
expect(isPowerOfTwoBitwise(7)).toBeFalsy();
expect(isPowerOfTwoBitwise(8)).toBeTruthy();
expect(isPowerOfTwoBitwise(10)).toBeFalsy();
expect(isPowerOfTwoBitwise(12)).toBeFalsy();
expect(isPowerOfTwoBitwise(16)).toBeTruthy();
expect(isPowerOfTwoBitwise(31)).toBeFalsy();
expect(isPowerOfTwoBitwise(64)).toBeTruthy();
expect(isPowerOfTwoBitwise(1024)).toBeTruthy();
expect(isPowerOfTwoBitwise(1023)).toBeFalsy();
});
});

View File

@ -0,0 +1,30 @@
/**
* @param {number} number
* @return {boolean}
*/
export default function isPowerOfTwo(number) {
// Don't work with negative numbers.
if (number < 0) {
throw new Error('Please provide positive number');
}
// 0 and 1 are not powers of two.
if (number <= 1) {
return false;
}
// Let's find out if we can divide the number by two
// many times without remainder.
let dividedNumber = number;
while (dividedNumber !== 1) {
if (dividedNumber % 2 !== 0) {
// For every case when remainder isn't zero we can say that this number
// couldn't be a result of power of two.
return false;
}
dividedNumber /= 2;
}
return true;
}

View File

@ -0,0 +1,31 @@
/**
* @param {number} number
* @return {boolean}
*/
export default function isPowerOfTwoBitwise(number) {
// Don't work with negative numbers.
if (number < 0) {
throw new Error('Please provide positive number');
}
// 0 and 1 are not powers of two.
if (number <= 1) {
return false;
}
/*
* Powers of two in binary look like this:
* 1: 0001
* 2: 0010
* 4: 0100
* 8: 1000
*
* Note that there is always exactly 1 bit set. The only exception is with a signed integer.
* e.g. An 8-bit signed integer with a value of -128 looks like:
* 10000000
*
* So after checking that the number is greater than zero, we can use a clever little bit
* hack to test that one and only one bit is set.
*/
return (number & (number - 1)) === 0;
}