mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-09-20 07:43:04 +08:00
Merge 1ea5d556c7
into ca3d16dcce
This commit is contained in:
commit
32405871c8
@ -1,7 +1,9 @@
|
|||||||
import isPowerOfTwo from '../isPowerOfTwo';
|
import isPowerOfTwo from '../isPowerOfTwo';
|
||||||
|
|
||||||
describe('isPowerOfTwo', () => {
|
describe('isPowerOfTwo', () => {
|
||||||
it('should detect if the number is power of two', () => {
|
it('should detect if the int is power of two', () => {
|
||||||
|
expect(isPowerOfTwo(-32)).toBe(false);
|
||||||
|
expect(isPowerOfTwo(-1)).toBe(false);
|
||||||
expect(isPowerOfTwo(1)).toBe(true);
|
expect(isPowerOfTwo(1)).toBe(true);
|
||||||
expect(isPowerOfTwo(2)).toBe(true);
|
expect(isPowerOfTwo(2)).toBe(true);
|
||||||
expect(isPowerOfTwo(3)).toBe(false);
|
expect(isPowerOfTwo(3)).toBe(false);
|
||||||
@ -16,5 +18,6 @@ describe('isPowerOfTwo', () => {
|
|||||||
expect(isPowerOfTwo(32)).toBe(true);
|
expect(isPowerOfTwo(32)).toBe(true);
|
||||||
expect(isPowerOfTwo(127)).toBe(false);
|
expect(isPowerOfTwo(127)).toBe(false);
|
||||||
expect(isPowerOfTwo(128)).toBe(true);
|
expect(isPowerOfTwo(128)).toBe(true);
|
||||||
|
expect(isPowerOfTwo(2 ** 30)).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,39 @@
|
|||||||
/**
|
/**
|
||||||
* @param {number} number
|
* @param {number} number
|
||||||
* @return bool
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
export default function isPowerOfTwo(number) {
|
export default function isPowerOfTwo(number) {
|
||||||
|
// 1 (2^0) is the smallest power 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.
|
||||||
|
*
|
||||||
|
* For example for number `8` the operations will look like:
|
||||||
|
*
|
||||||
|
* 1000
|
||||||
|
* - 0001
|
||||||
|
* ----
|
||||||
|
* 0111
|
||||||
|
*
|
||||||
|
* 1000
|
||||||
|
* & 0111
|
||||||
|
* ----
|
||||||
|
* 0000
|
||||||
|
*
|
||||||
|
* References: http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
|
||||||
|
*/
|
||||||
return (number & (number - 1)) === 0;
|
return (number & (number - 1)) === 0;
|
||||||
}
|
}
|
||||||
|
@ -1,51 +1,15 @@
|
|||||||
# Is a power of two
|
# Is a power of two
|
||||||
|
|
||||||
Given a positive integer, write a function to find if it is
|
Given a Real number, write a function to find if it is an integer power of the number 2, or not.
|
||||||
a power of two or not.
|
|
||||||
|
|
||||||
**Naive solution**
|
**Standard solution**
|
||||||
|
|
||||||
In naive solution we just keep dividing the number by two
|
We just keep dividing the number by two, unless the number becomes `1` and every time we do so,
|
||||||
unless the number becomes `1` and every time we do so, we
|
we check that remainder after division is always `0`. Otherwise, the number can't be a power of two.
|
||||||
check that remainder after division is always `0`. Otherwise, the number can't be a power of two.
|
|
||||||
|
|
||||||
**Bitwise solution**
|
**[Bitwise solution](https://github.com/Rudxain/javascript-algorithms/blob/master/src/algorithms/math/bits/isPowerOfTwo.js)**
|
||||||
|
|
||||||
Powers of two in binary form always have just one 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`)
|
|
||||||
|
|
||||||
```
|
|
||||||
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
|
## References
|
||||||
|
|
||||||
- [GeeksForGeeks](https://www.geeksforgeeks.org/program-to-find-whether-a-no-is-power-of-two/)
|
- [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)
|
- [Binary number subtraction on YouTube](https://www.youtube.com/watch?v=S9LJknZTyos&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=66)
|
||||||
|
@ -1,23 +1,27 @@
|
|||||||
import isPowerOfTwo from '../isPowerOfTwo';
|
import f from '../isPowerOfTwo';
|
||||||
|
|
||||||
describe('isPowerOfTwo', () => {
|
describe('isPowerOfTwo', () => {
|
||||||
it('should check if the number is made by multiplying twos', () => {
|
it('should check if the number is made by multiplying twos', () => {
|
||||||
expect(isPowerOfTwo(-1)).toBe(false);
|
// test all pows until it gets as close as possible to `Number.MAX_VALUE`
|
||||||
expect(isPowerOfTwo(0)).toBe(false);
|
for (let i = 0; i <= 0x3ff; i++) {
|
||||||
expect(isPowerOfTwo(1)).toBe(true);
|
expect( f(2 ** i) && f(1n << BigInt(i)) ).toBe(true)
|
||||||
expect(isPowerOfTwo(2)).toBe(true);
|
}
|
||||||
expect(isPowerOfTwo(3)).toBe(false);
|
expect(f(-8.5)).toBe(false);
|
||||||
expect(isPowerOfTwo(4)).toBe(true);
|
expect(f(-1) || f(-1n)).toBe(false);
|
||||||
expect(isPowerOfTwo(5)).toBe(false);
|
expect(f(0) || f(0n)).toBe(false);
|
||||||
expect(isPowerOfTwo(6)).toBe(false);
|
expect(f(0.5)).toBe(false);
|
||||||
expect(isPowerOfTwo(7)).toBe(false);
|
expect(f(Math.E)).toBe(false);
|
||||||
expect(isPowerOfTwo(8)).toBe(true);
|
expect(f(3) || f(3n)).toBe(false);
|
||||||
expect(isPowerOfTwo(10)).toBe(false);
|
expect(f(Math.PI)).toBe(false);
|
||||||
expect(isPowerOfTwo(12)).toBe(false);
|
expect(f(5) || f(5n)).toBe(false);
|
||||||
expect(isPowerOfTwo(16)).toBe(true);
|
expect(f(6) || f(6n)).toBe(false);
|
||||||
expect(isPowerOfTwo(31)).toBe(false);
|
expect(f(7) || f(7n)).toBe(false);
|
||||||
expect(isPowerOfTwo(64)).toBe(true);
|
expect(f(10) || f(10n)).toBe(false);
|
||||||
expect(isPowerOfTwo(1024)).toBe(true);
|
expect(f(12) || f(12n)).toBe(false);
|
||||||
expect(isPowerOfTwo(1023)).toBe(false);
|
expect(f(31) || f(31n)).toBe(false);
|
||||||
|
expect(f(1023) || f(1023n)).toBe(false);
|
||||||
|
expect( f(2 ** 32 - 1) || f(~(-1n << 32n)) ).toBe(false);
|
||||||
|
expect(f(Infinity) || f(-Infinity)).toBe(false);
|
||||||
|
expect(f(NaN)).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import isPowerOfTwoBitwise from '../isPowerOfTwoBitwise';
|
|
||||||
|
|
||||||
describe('isPowerOfTwoBitwise', () => {
|
|
||||||
it('should check if the number is made by multiplying twos', () => {
|
|
||||||
expect(isPowerOfTwoBitwise(-1)).toBe(false);
|
|
||||||
expect(isPowerOfTwoBitwise(0)).toBe(false);
|
|
||||||
expect(isPowerOfTwoBitwise(1)).toBe(true);
|
|
||||||
expect(isPowerOfTwoBitwise(2)).toBe(true);
|
|
||||||
expect(isPowerOfTwoBitwise(3)).toBe(false);
|
|
||||||
expect(isPowerOfTwoBitwise(4)).toBe(true);
|
|
||||||
expect(isPowerOfTwoBitwise(5)).toBe(false);
|
|
||||||
expect(isPowerOfTwoBitwise(6)).toBe(false);
|
|
||||||
expect(isPowerOfTwoBitwise(7)).toBe(false);
|
|
||||||
expect(isPowerOfTwoBitwise(8)).toBe(true);
|
|
||||||
expect(isPowerOfTwoBitwise(10)).toBe(false);
|
|
||||||
expect(isPowerOfTwoBitwise(12)).toBe(false);
|
|
||||||
expect(isPowerOfTwoBitwise(16)).toBe(true);
|
|
||||||
expect(isPowerOfTwoBitwise(31)).toBe(false);
|
|
||||||
expect(isPowerOfTwoBitwise(64)).toBe(true);
|
|
||||||
expect(isPowerOfTwoBitwise(1024)).toBe(true);
|
|
||||||
expect(isPowerOfTwoBitwise(1023)).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,24 +1,37 @@
|
|||||||
/**
|
/**
|
||||||
* @param {number} number
|
* @param {number|bigint} numeric value to check
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
export default function isPowerOfTwo(number) {
|
export default function isPowerOfTwo(x) {
|
||||||
// 1 (2^0) is the smallest power of two.
|
// 1 (2^0) is the smallest power of two.
|
||||||
if (number < 1) {
|
if (x <= 1) {
|
||||||
return false;
|
return x == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// guard clause to dispatch BigInts ASAP
|
||||||
|
if (typeof x == "bigint") {
|
||||||
|
// the bitwise alt works for any BigInt
|
||||||
|
// because bit operators are arbitrary-precision for them
|
||||||
|
return (x & (x - 1n)) === 0n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's find out if we can divide the number by two
|
// Let's find out if we can divide the number by two
|
||||||
// many times without remainder.
|
// many times without remainder.
|
||||||
let dividedNumber = number;
|
let dividedNum = x / 2;
|
||||||
while (dividedNumber !== 1) {
|
while (dividedNum !== 1) {
|
||||||
if (dividedNumber % 2 !== 0) {
|
if ( !Number.isInteger(dividedNum) ) {
|
||||||
// For every case when remainder isn't zero we can say that this number
|
/*
|
||||||
// couldn't be a result of power of two.
|
For every case when quotient is non-int we can say that this number
|
||||||
|
couldn't be a result of power of two (with integer exponent),
|
||||||
|
because checking the fractional part of a quotient is equivalent to checking if the remainder is 0,
|
||||||
|
and the remainder is the value of the least significant bit (with fractional part included).
|
||||||
|
All powers of 2 (but `1`) must have consecutive trailing zeros.
|
||||||
|
this also immediately dispatches non-int values of `x`, because neither rem nor quotient is an int
|
||||||
|
*/
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dividedNumber /= 2;
|
dividedNum /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param {number} number
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
export default function isPowerOfTwoBitwise(number) {
|
|
||||||
// 1 (2^0) is the smallest power 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;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user