Today I needed a simple algorithm for checking if a number is a power of 2.
The algorithm needs to be:
Simple
Correct for any ulong value.
I came up with this simple algorithm:
private bool IsPowerOfTwo(ulong number)
{
if (number == 0)
return false;
for (ulong power = 1; power > 0; power = power << 1)
{
// This for loop used shifting for powers of 2, meaning
// that the value will become 0 after the last shift
// (from binary 1000...0000 to 0000...0000) then, the 'for'
// loop will break out.
if (power == number)
return true;
if (power > number)
return false;
}
return false;
}
But then I thought: How about checking if log2 x is an exactly a round number? When I checked for 2^63+1, Math.Log() returned exactly 63 because of rounding. So I checked if 2 to the power 63 is equal to the original number and it is, because the calculation is done in doubles and not in exact numbers.
private bool IsPowerOfTwo_2(ulong number)
{
double log = Math.Log(number, 2);
double pow = Math.Pow(2, Math.Round(log));
return pow == number;
}
This returned true for the given wrong value: 9223372036854775809.
Is there a better algorithm?
There's a simple trick for this problem:
bool IsPowerOfTwo(ulong x)
{
return (x & (x - 1)) == 0;
}
Note, this function will report true for 0, which is not a power of 2. If you want to exclude that, here's how:
bool IsPowerOfTwo(ulong x)
{
return (x != 0) && ((x & (x - 1)) == 0);
}
Explanation
First and foremost the bitwise binary & operator from MSDN definition:
Binary & operators are predefined for the integral types and bool. For
integral types, & computes the logical bitwise AND of its operands.
For bool operands, & computes the logical AND of its operands; that
is, the result is true if and only if both its operands are true.
Now let's take a look at how this all plays out:
The function returns boolean (true / false) and accepts one incoming parameter of type unsigned long (x, in this case). Let us for the sake of simplicity assume that someone has passed the value 4 and called the function like so:
bool b = IsPowerOfTwo(4)
Now we replace each occurrence of x with 4:
return (4 != 0) && ((4 & (4-1)) == 0);
Well we already know that 4 != 0 evals to true, so far so good. But what about:
((4 & (4-1)) == 0)
This translates to this of course:
((4 & 3) == 0)
But what exactly is 4&3?
The binary representation of 4 is 100 and the binary representation of 3 is 011 (remember the & takes the binary representation of these numbers). So we have:
100 = 4
011 = 3
Imagine these values being stacked up much like elementary addition. The & operator says that if both values are equal to 1 then the result is 1, otherwise it is 0. So 1 & 1 = 1, 1 & 0 = 0, 0 & 0 = 0, and 0 & 1 = 0. So we do the math:
100
011
----
000
The result is simply 0. So we go back and look at what our return statement now translates to:
return (4 != 0) && ((4 & 3) == 0);
Which translates now to:
return true && (0 == 0);
return true && true;
We all know that true && true is simply true, and this shows that for our example, 4 is a power of 2.
Some sites that document and explain this and other bit twiddling hacks are:
http://graphics.stanford.edu/~seander/bithacks.html
(http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2)
http://bits.stephan-brumme.com/
(http://bits.stephan-brumme.com/isPowerOfTwo.html)
And the grandaddy of them, the book "Hacker's Delight" by Henry Warren, Jr.:
http://www.hackersdelight.org/
As Sean Anderson's page explains, the expression ((x & (x - 1)) == 0) incorrectly indicates that 0 is a power of 2. He suggests to use:
(!(x & (x - 1)) && x)
to correct that problem.
return (i & -i) == i
The following addendum to the accepted answer may be useful for some people:
A power of two, when expressed in binary, will always look like 1 followed by n zeroes where n is greater than or equal to 0. Ex:
Decimal Binary
1 1 (1 followed by 0 zero)
2 10 (1 followed by 1 zero)
4 100 (1 followed by 2 zeroes)
8 1000 (1 followed by 3 zeroes)
. .
. .
. .
and so on.
When we subtract 1 from these kind of numbers, they become 0 followed by n ones and again n is same as above. Ex:
Decimal Binary
1 - 1 = 0 0 (0 followed by 0 one)
2 - 1 = 1 01 (0 followed by 1 one)
4 - 1 = 3 011 (0 followed by 2 ones)
8 - 1 = 7 0111 (0 followed by 3 ones)
. .
. .
. .
and so on.
Coming to the crux
What happens when we do a bitwise AND of a number x, which is a
power of 2, and x - 1?
The one of x gets aligned with the zero of x - 1 and all the zeroes of x get aligned with ones of x - 1, causing the bitwise AND to result in 0. And that is how we have the single line answer mentioned above being right.
Further adding to the beauty of accepted answer above -
So, we have a property at our disposal now:
When we subtract 1 from any number, then in the binary representation the rightmost 1 will become 0 and all the zeroes to the left of that rightmost 1 will now become 1.
One awesome use of this property is in finding out - How many 1s are present in the binary representation of a given number? The short and sweet code to do that for a given integer x is:
byte count = 0;
for ( ; x != 0; x &= (x - 1)) count++;
Console.Write("Total ones in the binary representation of x = {0}", count);
Another aspect of numbers that can be proved from the concept explained above is "Can every positive number be represented as the sum of powers of 2?".
Yes, every positive number can be represented as the sum of powers of 2. For any number, take its binary representation. Ex: Take number 117.
The binary representation of 117 is 1110101
Because 1110101 = 1000000 + 100000 + 10000 + 0000 + 100 + 00 + 1
we have 117 = 64 + 32 + 16 + 0 + 4 + 0 + 1
bool IsPowerOfTwo(ulong x)
{
return x > 0 && (x & (x - 1)) == 0;
}
Here's a simple C++ solution:
bool IsPowerOfTwo( unsigned int i )
{
return std::bitset<32>(i).count() == 1;
}
After posting the question I thought of the following solution:
We need to check if exactly one of the binary digits is one. So we simply shift the number right one digit at a time, and return true if it equals 1. If at any point we come by an odd number ((number & 1) == 1), we know the result is false. This proved (using a benchmark) slightly faster than the original method for (large) true values and much faster for false or small values.
private static bool IsPowerOfTwo(ulong number)
{
while (number != 0)
{
if (number == 1)
return true;
if ((number & 1) == 1)
// number is an odd number and not 1 - so it's not a power of two.
return false;
number = number >> 1;
}
return false;
}
Of course, Greg's solution is much better.
bool IsPowerOfTwo(int n)
{
if (n > 1)
{
while (n%2 == 0)
{
n >>= 1;
}
}
return n == 1;
}
And here's a general algorithm for finding out if a number is a power of another number.
bool IsPowerOf(int n,int b)
{
if (n > 1)
{
while (n % b == 0)
{
n /= b;
}
}
return n == 1;
}
bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;
bool isPowerOfTwo(int x_)
{
register int bitpos, bitpos2;
asm ("bsrl %1,%0": "+r" (bitpos):"rm" (x_));
asm ("bsfl %1,%0": "+r" (bitpos2):"rm" (x_));
return bitpos > 0 && bitpos == bitpos2;
}
int isPowerOfTwo(unsigned int x)
{
return ((x != 0) && ((x & (~x + 1)) == x));
}
This is really fast. It takes about 6 minutes and 43 seconds to check all 2^32 integers.
return ((x != 0) && !(x & (x - 1)));
If x is a power of two, its lone 1 bit is in position n. This means x – 1 has a 0 in position n. To see why, recall how a binary subtraction works. When subtracting 1 from x, the borrow propagates all the way to position n; bit n becomes 0 and all lower bits become 1. Now, since x has no 1 bits in common with x – 1, x & (x – 1) is 0, and !(x & (x – 1)) is true.
Find if the given number is a power of 2.
#include <math.h>
int main(void)
{
int n,logval,powval;
printf("Enter a number to find whether it is s power of 2\n");
scanf("%d",&n);
logval=log(n)/log(2);
powval=pow(2,logval);
if(powval==n)
printf("The number is a power of 2");
else
printf("The number is not a power of 2");
getch();
return 0;
}
for any power of 2, the following also holds.
n&(-n)==n
NOTE: fails for n=0 , so need to check for it
Reason why this works is:
-n is the 2s complement of n. -n will have every bit to the left of rightmost set bit of n flipped compared to n. For powers of 2 there is only one set bit.
A number is a power of 2 if it contains only 1 set bit. We can use this property and the generic function countSetBits to find if a number is power of 2 or not.
This is a C++ program:
int countSetBits(int n)
{
int c = 0;
while(n)
{
c += 1;
n = n & (n-1);
}
return c;
}
bool isPowerOfTwo(int n)
{
return (countSetBits(n)==1);
}
int main()
{
int i, val[] = {0,1,2,3,4,5,15,16,22,32,38,64,70};
for(i=0; i<sizeof(val)/sizeof(val[0]); i++)
printf("Num:%d\tSet Bits:%d\t is power of two: %d\n",val[i], countSetBits(val[i]), isPowerOfTwo(val[i]));
return 0;
}
We dont need to check explicitly for 0 being a Power of 2, as it returns False for 0 as well.
OUTPUT
Num:0 Set Bits:0 is power of two: 0
Num:1 Set Bits:1 is power of two: 1
Num:2 Set Bits:1 is power of two: 1
Num:3 Set Bits:2 is power of two: 0
Num:4 Set Bits:1 is power of two: 1
Num:5 Set Bits:2 is power of two: 0
Num:15 Set Bits:4 is power of two: 0
Num:16 Set Bits:1 is power of two: 1
Num:22 Set Bits:3 is power of two: 0
Num:32 Set Bits:1 is power of two: 1
Num:38 Set Bits:3 is power of two: 0
Num:64 Set Bits:1 is power of two: 1
Num:70 Set Bits:3 is power of two: 0
Here is another method I devised, in this case using | instead of & :
bool is_power_of_2(ulong x) {
if(x == (1 << (sizeof(ulong)*8 -1) ) return true;
return (x > 0) && (x<<1 == (x|(x-1)) +1));
}
It's very easy in .Net 6 now.
using System.Numerics;
bool isPow2 = BitOperations.IsPow2(64); // sets true
Here is the documentation.
Example
0000 0001 Yes
0001 0001 No
Algorithm
Using a bit mask, divide NUM the variable in binary
IF R > 0 AND L > 0: Return FALSE
Otherwise, NUM becomes the one that is non-zero
IF NUM = 1: Return TRUE
Otherwise, go to Step 1
Complexity
Time ~ O(log(d)) where d is number of binary digits
There is a one liner in .NET 6
// IsPow2 evaluates whether the specified Int32 value is a power of two.
Console.WriteLine(BitOperations.IsPow2(128)); // True
Improving the answer of #user134548, without bits arithmetic:
public static bool IsPowerOfTwo(ulong n)
{
if (n % 2 != 0) return false; // is odd (can't be power of 2)
double exp = Math.Log(n, 2);
if (exp != Math.Floor(exp)) return false; // if exp is not integer, n can't be power
return Math.Pow(2, exp) == n;
}
This works fine for:
IsPowerOfTwo(9223372036854775809)
Mark gravell suggested this if you have .NET Core 3, System.Runtime.Intrinsics.X86.Popcnt.PopCount
public bool IsPowerOfTwo(uint i)
{
return Popcnt.PopCount(i) == 1
}
Single instruction, faster than (x != 0) && ((x & (x - 1)) == 0) but less portable.
in this approach , you can check if there is only 1 set bit in the integer and the integer is > 0 (c++).
bool is_pow_of_2(int n){
int count = 0;
for(int i = 0; i < 32; i++){
count += (n>>i & 1);
}
return count == 1 && n > 0;
}
In C, I tested the i && !(i & (i - 1) trick and compared it with __builtin_popcount(i), using gcc on Linux, with the -mpopcnt flag to be sure to use the CPU's POPCNT instruction. My test program counted the # of integers between 0 and 2^31 that were a power of two.
At first I thought that i && !(i & (i - 1) was 10% faster, even though I verified that POPCNT was used in the disassembly where I used__builtin_popcount.
However, I realized that I had included an if statement, and branch prediction was probably doing better on the bit twiddling version. I removed the if and POPCNT ended up faster, as expected.
Results:
Intel(R) Core(TM) i7-4771 CPU max 3.90GHz
Timing (i & !(i & (i - 1))) trick
30
real 0m13.804s
user 0m13.799s
sys 0m0.000s
Timing POPCNT
30
real 0m11.916s
user 0m11.916s
sys 0m0.000s
AMD Ryzen Threadripper 2950X 16-Core Processor max 3.50GHz
Timing (i && !(i & (i - 1))) trick
30
real 0m13.675s
user 0m13.673s
sys 0m0.000s
Timing POPCNT
30
real 0m13.156s
user 0m13.153s
sys 0m0.000s
Note that here the Intel CPU seems slightly slower than AMD with the bit twiddling, but has a much faster POPCNT; the AMD POPCNT doesn't provide as much of a boost.
popcnt_test.c:
#include "stdio.h"
// Count # of integers that are powers of 2 up to 2^31;
int main() {
int n;
for (int z = 0; z < 20; z++){
n = 0;
for (unsigned long i = 0; i < 1<<30; i++) {
#ifdef USE_POPCNT
n += (__builtin_popcount(i)==1); // Was: if (__builtin_popcount(i) == 1) n++;
#else
n += (i && !(i & (i - 1))); // Was: if (i && !(i & (i - 1))) n++;
#endif
}
}
printf("%d\n", n);
return 0;
}
Run tests:
gcc popcnt_test.c -O3 -o test.exe
gcc popcnt_test.c -O3 -DUSE_POPCNT -mpopcnt -o test-popcnt.exe
echo "Timing (i && !(i & (i - 1))) trick"
time ./test.exe
echo
echo "Timing POPCNT"
time ./test-opt.exe
I see many answers are suggesting to return n && !(n & (n - 1)) but to my experience if the input values are negative it returns false values.
I will share another simple approach here since we know a power of two number have only one set bit so simply we will count number of set bit this will take O(log N) time.
while (n > 0) {
int count = 0;
n = n & (n - 1);
count++;
}
return count == 1;
Check this article to count no. of set bits
This is another method to do it as well
package javacore;
import java.util.Scanner;
public class Main_exercise5 {
public static void main(String[] args) {
// Local Declaration
boolean ispoweroftwo = false;
int n;
Scanner input = new Scanner (System.in);
System.out.println("Enter a number");
n = input.nextInt();
ispoweroftwo = checkNumber(n);
System.out.println(ispoweroftwo);
}
public static boolean checkNumber(int n) {
// Function declaration
boolean ispoweroftwo= false;
// if not divisible by 2, means isnotpoweroftwo
if(n%2!=0){
ispoweroftwo=false;
return ispoweroftwo;
}
else {
for(int power=1; power>0; power=power<<1) {
if (power==n) {
return true;
}
else if (power>n) {
return false;
}
}
}
return ispoweroftwo;
}
}
This one returns if the number is the power of two up to 64 value ( you can change it inside for loop condition ("6" is for 2^6 is 64);
const isPowerOfTwo = (number) => {
let result = false;
for (let i = 1; i <= 6; i++) {
if (number === Math.pow(2, i)) {
result = true;
}
}
return result;
};
console.log(isPowerOfTwo(16));
console.log(isPowerOfTwo(10));
I've been reading the documentation for Random.nextInt(int bound) and saw this nice piece of code which checks whether the parameter is a power of 2, which says (part of the code) :
if ((bound & -bound) == bound) // ie, bouns is a power of 2
let's test it
for (int i=0; i<=8; i++) {
System.out.println(i+" = " + Integer.toBinaryString(i));
}
>>
0 = 0
1 = 1
2 = 10
3 = 11
4 = 100
5 = 101
6 = 110
7 = 111
8 = 1000
// the left most 0 bits where cut out of the output
for (int i=-1; i>=-8; i--) {
System.out.println(i+" = " + Integer.toBinaryString(i));
}
>>
-1 = 11111111111111111111111111111111
-2 = 11111111111111111111111111111110
-3 = 11111111111111111111111111111101
-4 = 11111111111111111111111111111100
-5 = 11111111111111111111111111111011
-6 = 11111111111111111111111111111010
-7 = 11111111111111111111111111111001
-8 = 11111111111111111111111111111000
did you notice something ?
power 2 number have the same bits in the positive and the negative binary representation, if we do a logical AND we get the same number :)
for (int i=0; i<=8; i++) {
System.out.println(i + " & " + (-i)+" = " + (i & (-i)));
}
>>
0 & 0 = 0
1 & -1 = 1
2 & -2 = 2
3 & -3 = 1
4 & -4 = 4
5 & -5 = 1
6 & -6 = 2
7 & -7 = 1
8 & -8 = 8
Kotlin:
fun isPowerOfTwo(n: Int): Boolean {
return (n > 0) && (n.and(n-1) == 0)
}
or
fun isPowerOfTwo(n: Int): Boolean {
if (n == 0) return false
return (n and (n - 1).inv()) == n
}
inv inverts the bits in this value.
Note:
log2 solution doesn't work for large numbers, like 536870912 ->
import kotlin.math.truncate
import kotlin.math.log2
fun isPowerOfTwo(n: Int): Boolean {
return (n > 0) && (log2(n.toDouble())) == truncate(log2(n.toDouble()))
}
There were a number of answers and posted links explaining why the n & (n-1) == 0 works for powers of 2, but I couldn't find any explanation of why it doesn't work for non-powers of 2, so I'm adding this just for completeness.
For n = 1 (2^0 = 1), 1 & 0 = 0, so we are fine.
For odd n > 1, there are at least 2 bits of 1 (left-most and right-most bits). Now n and n-1 will only differ by the right-most bit, so their &-sum will at least have a 1 on the left-most bit, so n & (n-1) != 0:
n: 1xxxx1 for odd n > 1
n-1: 1xxxx0
------
n & (n-1): 1xxxx0 != 0
Now for even n that is not a power of 2, we also have at least 2 bits of 1 (left-most and non-right-most). Here, n and n-1 will differ up to the right-most 1 bit, so their &-sum will also have at least a 1 on the left-most bit:
right-most 1 bit of n
v
n: 1xxxx100..00 for even n
n-1: 1xxxx011..11
------------
n & (n-1): 1xxxx000..00 != 0
I'm assuming 1 is a power of two, which it is, it's 2 to the power of zero
bool IsPowerOfTwo(ulong testValue)
{
ulong bitTest = 1;
while (bitTest != 0)
{
if (bitTest == testValue) return true;
bitTest = bitTest << 1;
}
return false;
}
I know that the << operand shifts the left value of the operand with the value on the right with bits. So 1 << 2 would give 4. And the | operand copies a bit if it exists in either value. But I simply can't get my head around the code.
private static bool isPandigital(long n)
{
int digits = 0;
int count = 0;
int tmp;
while (n > 0)
{
tmp = digits;
digits = digits | 1 << (int)((n % 10) - 1);
if (tmp == digits)
{
return false;
}
count++;
n /= 10;
}
return digits == (1 << count) - 1;
}
Why does it say 1 << in line 8? And why is the module - 1?
On top of that I don't know what is happening on the last line when the value is returned. Help would be greatly apreciated. Thanks very much!
Doing
digits = digits | 1 << (int)((n % 10) - 1);
is the same thing as
long temp1 = n % 10; //Divide the number by 10 and get the remainder
long temp2 = temp1 - 1; //Subtract 1 from the remainder.
int temp3 = (int)temp2; //cast the subtracted value to int
int temp4 = 1 << temp3; //left shift 1 to the casted value. This is the same as saying "two to the power of the value of temp3"
int temp5 = digits | temp4; //bitwise or together the values of digits and that leftshifted number.
digits = temp5; //Assign the or'ed value back to digits.
The last line
return digits == (1 << count) - 1;
is just doing the same thing as
int temp1 = 1 << count; //left shift 1 `count` times, this is the same as saying "two to the power of the value of count"
int temp2 = temp1 - 1; //Subtract 1 from the leftshifted number.
bool temp3 = digits == temp2; //test to see if digits equals temp2
return temp3;
I don't know what "pandigital" means, but this break apart can help you understand what is happening.
If pandigital means "contains all possible digits for the given radix"
https://en.wikipedia.org/wiki/Pandigital_number
and the radix == 10, why not just check if the number contains all possible 0..9 digits:
private static bool isPandigital(long n) {
// I assume negative numbers cannot be pandigital;
// if they can, put n = Math.Abs(n);
if (n < 1023456789) // smallest pandigital
return false;
int[] digits = new int[10];
for (; n > 0; n /= 10)
digits[n % 10] += 1;
return digits.All(item => item > 0);
}
Edit: In case of bit array (each bit in digits represent a digit) implementation:
private static bool isPandigital(long n) {
// negative numbers can't be pandigital
if (n < 1023456789) // smallest pandigital
return false;
int digits = 0;
for (; n > 0; n /= 10)
digits |= (1 << (int)(n % 10));
// 0b1111111111
return digits == 1023;
}
I think the writer of the method attempted to do this:
static bool IsPandigital(long n) {
int digits = 0;
while (n > 0) {
//set the bit corresponding to the last digit of n to 1 (true)
digits |= 1 << (int)(n % 10);
//remove the last digit of n
n /= 10;
}
//digits must be equal to 1111111111 (in binary)
return digits == (1 << 10) - 1;
}
The << operator is not that difficult. You just have to think in binary.
1 << 0 is simply a 1 shifted zero places, so 1
1 << 1 is 10
1 << 2 is 100, etc
If you encounter a 2 and a 5 and you 'or' them together you will have 100100.
This means if you encounter all 10 digits, the end result will be ten 1's.
In the return statement, we check if digits equals ten 1's.
1 << 10 means a 10000000000. If you substract 1, you get 1111111111
All this in binary, of course.
He may have had a different definition of pandigital, or just a different requirement. If, for example zeroes are not allowed, you can simply change the last line to: digits == (1 << 10) - 2;
The task is to find a triangle number which has at least 500 divisors.
For example 28 has 6 divisors: 1,2,4,7,14,28
My code works for up to 200 divisors, but for 500 it runs forever...
Is there any way to optimize the code. For instance I thought of dynamic optimization and memoization, but couldn't find a way to do it?
int sum = 0;
int counter = 0;
int count = 1;
bool isTrue = true;
while (isTrue)
{
counter = 0;
sum += count;
for (int j = 1; j <= sum; j++)
{
if (sum % j == 0)
{
counter++;
if (counter == 500)
{
isTrue = false;
Console.WriteLine("Triangle number: {0}", sum);
break;
}
}
}
count++;
}
Console.WriteLine("Number of divisors: {0}", counter);
Ignore the fact that the number is a triangle number. If you can solve this problem quickly:
given any number n, determine the number of divisors it has
then obviously you can solve Euler #12 quickly. Just list the triangle numbers, which are easy to calculate, determine the number of divisors of each, and stop when you get a result 500 or larger.
So how do you determine the number of divisors quickly? As you've discovered, when the numbers get big, it's a lot of work.
Here's a hint. Suppose you already have the prime factorization. Let's pick a number, say, 196. Factorize that into prime numbers:
196 = 2 x 2 x 7 x 7
I can tell you just by glancing at the factorization that 196 has nine divisors. How?
Because any divisor of 196 is of the form:
(1, 2 or 2x2) x (1, 7 or 7x7)
So obviously there are nine possible combinations:
1 x 1
1 x 7
1 x 7 x 7
2 x 1
2 x 7
2 x 7 x 7
2 x 2 x 1
2 x 2 x 7
2 x 2 x 7 x 7
Pick another number. 200, lets say. Thats 2 x 2 x 2 x 5 x 5. So there are twelve possibilities:
1 x 1
1 x 5
1 x 5 x 5
2 x 1
2 x 5
...
2 x 2 x 2 x 5 x 5
See the pattern? You take the prime factorization, group them by prime, and count how many are in each group. Then you add one to each of those numbers and multiply them together. Again, in 200 there are three twos and two fives in the prime factorization. Add one to each: four and three. Multiply them together: twelve. That's how many divisors there are.
So you can find the number of divisors very quickly if you know the prime factorization. We have reduced the divisor problem to a much easier problem: Can you figure out how to produce a prime factorization quickly?
here are some optimizations I'll just throw out there for you.
the easiest thing is to change
for (int j = 1; j <= sum; j++)
{
if (sum % j == 0)
{
counter++;
if (counter == 500)
{
isTrue = false;
Console.WriteLine("Triangle number: {0}", sum);
break;
}
}
}
if you've found 1 divisor, you've found 2 divisors, so change it to
for (int j = 1; j <= sum; j++)
{
if (sum % j == 0)
{
if(sum/j < j)
break;
else if(sum/j == j)
counter++;
else
counter +=2;
if (counter == 500)
{
isTrue = false;
Console.WriteLine("Triangle number: {0}", sum);
break;
}
}
}
this will reduce the runtime a lot, but it will still take a long time.
another optimization you can do is to not start checking form sum but calculate the smallest number that has 500 divisors.
and then you can find the largest triangle number after that, and start from there.
If you can figure something else special about the nature of this problem, than it is possible for you to reduce the runtime by a whole lot.
The number of divisors of a number is the product of the powers of the prime factors plus one. For example: 28 = 2^2*7^1, so the # of divisors is (2+1)*(1+1) = 6.
This means that, if you want many divisors compared to the size of the number, you don't want any one prime to occur too often. Put another way: it is likely that the smallest triangular number with at least 500 divisors is the product of small powers of small primes.
So, instead of checking every number to see if it divides the triangular number, go through a list of the smallest primes, and see how often each one occurs in the prime factorization. Then use the formula above to compute the number of divisors.
Take these steps:
1.) Calculate the first log(2, 499) prime numbers (not 500, as 1 is counted as a divisor if I am nit mistaken despite the fact that it is not prime, as it has only one divisor). There are many solutions out there, but you catch my drift.
2.) A triangle number is of the form of n * (n + 1) / 2, because
1 + 2 + ... + 100 = (1 + 100) + (2 + 99) + ... + (50 + 51) = 101 * 50 = 101 * 100 / 2 = 5050 (as Cauchy solved it when he was an eight-year boy and the teacher punished him with this task).
1 + ... + n = (1 + n) + (2 + n - 1) + ... = n * (n + 1) / 2.
3.) S = prod(first log(2, 499) prime numbers)
4.) Solve the equation of n * (n + 1) / 2 = S and calculate its ceiling. You will have an integer, let's call it m.
5.)
while (not(found))
found = isCorrect(m)
if (not(found)) then
m = m + 1
end if
end while
return m
and there you go. Let me know if I was able to help you.
As #EricLippert nad #LajosArpad mentioned, the key idea is to iterate over triangle numbers only. You can calculate them using the following formula:
T(n) = n * (n + 1) / 2
Here is JSFiddle which you may find helpful.
function generateTriangleNumber(n) {
return (n * (n + 1)) / 2;
}
function findTriangleNumberWithOver500Divisors() {
var nextTriangleNum;
var sqrt;
for (i = 2;; i++) {
var factors = [];
factors[0] = 1;
nextTriangleNum = generateTriangleNumber(i);
sqrt = Math.pow(nextTriangleNum, 0.5);
sqrt = Math.floor(sqrt);
var j;
for (j = 2; j <= sqrt; j++) {
if (nextTriangleNum % j == 0) {
var quotient = nextTriangleNum / j;
factors[factors.length] = j;
factors[factors.length] = quotient;
}
}
factors[factors.length] = nextTriangleNum;
if (factors.length > 500) {
break;
}
}
console.log(nextTriangleNum);
}
Incidentally, the first Google result for divisors of triangular number search query gives this :)
Project Euler 12: Triangle Number with 500 Divisors
See if it helps.
EDIT: Text from that article:
The first triangle number with over 500 digits is: 76576500 Solution
took 1 ms
Is there a simple math function available that compares numbers x and y and returns -1 when x is less than y, 1 when x is more than y and 0 when they're equal?
If not, would there be a elegant solution (without any if's) to convert the output of Math.Max(x, y) to these returns? I was thinking of dividing the numbers by themselves, e.g. 123/123 = 1 but that will introduce the problem of dividing by 0.
For your strict -1, 0 or 1 requirement, there's no single method that is guaranteed to do this. However, you can use a combination of Int32.CompareTo and Math.Sign:
int value = Math.Sign(x.CompareTo(y));
Alternatively, if you're happy with the normal CompareTo contract which is just stated in terms of negative numbers, positive numbers and 0, you can use CompareTo on its own.
You can do it without using any .NET calls at all and on 1 line. NOTE: Math.Sign and type.CompareTo both use logical if statements and comparison operators which you said you wanted to avoid.
int result = (((x - y) >> 0x1F) | (int)((uint)(-(x - y)) >> 0x1F));
as a function
//returns 0 if equal
//returns 1 if x > y
//returns -1 if x < y
public int Compare(int x, int y)
{
return (((x - y) >> 0x1F) | (int)((uint)(-(x - y)) >> 0x1F));
}
Basically, all this does is SHIFT the sign bits all the way to the first position. If the result is unsigned then it will be 0; then it does the same operation and flips the sign bits then ORs them together and the result is wither 1, 0 or -1.
Case where result is -1
IS 12 > 15:
12 - 15 = -3 (11111111111111111111111111111101)
-3 >> 0x1F = -1 (11111111111111111111111111111111)
-(12 - 15) = 3 (00000000000000000000000000000011)
3 >> 0x1F = ((uint)0)=0 (00000000000000000000000000000000) cast to uint so 0
11111111111111111111111111111111
OR
00000000000000000000000000000000
= 11111111111111111111111111111111 (-1)
Case where result is 1
IS 15 > 12:
15 - 12 = 3 (00000000000000000000000000000011)
3 >> 0x1F = 0 (00000000000000000000000000000000)
-(15 - 12) = -3 (11111111111111111111111111111101)
-3 >> 0x1F = ((uint)-1)=1 (00000000000000000000000000000001) cast to uint so 1
00000000000000000000000000000000
OR
00000000000000000000000000000001
= 00000000000000000000000000000001 (1)
Case where result is 0
IS 15 == 15:
15 - 15 = 0 (00000000000000000000000000000000)
0 >> 0x1F = 0 (00000000000000000000000000000000)
-(15 - 15) = 0 (00000000000000000000000000000000)
0 >> 0x1F = ((uint)0)=0 (00000000000000000000000000000000) cast to uint so 1
00000000000000000000000000000000
OR
00000000000000000000000000000000
= 00000000000000000000000000000000 (0)
This should also be much faster than using any calls to Math or any other .NET methods.
x.CompareTo(y)
Straight from MSDN.
Use the CompareTo() function
int i = 5;
int n = 6;
int c = i.CompareTo(n);
I generally use it in if statements:
int x = 34;
int y = 25;
if(x.CompareTo(y) == 0)
{
Console.WriteLine("Yes, they are equal");
}
else
{
Console.WriteLine("No, they are not equal");
}
Edit:
After some people claimed that Int32.CompareTo() could return something other than -1|0|1, I decided to research the possibility myself.
Here's the reflected code for Int32.CompareTo(). I fail to see how either one would ever return anything but -1|0|1.
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public int CompareTo(int value)
{
if (this < value)
{
return -1;
}
if (this > value)
{
return 1;
}
return 0;
}
public int CompareTo(object value)
{
if (value == null)
{
return 1;
}
if (!(value is int))
{
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeInt32"));
}
int num = (int) value;
if (this < num)
{
return -1;
}
if (this > num)
{
return 1;
}
return 0;
}
It's the Math.Sign() function.
Like this:
return Math.Sign(x-y);
you can try with this code
var result = a.CompareTo(b);
Use the CompareTo Method on an integer:
public int c(int x, int y)
{
return x.CompareTo(y);
}
void Main()
{
Console.WriteLine(c(5,3));
Console.WriteLine(c(3,3));
Console.WriteLine(c(1,3));
}
You tried use compareTo()? Look here: http://msdn.microsoft.com/en-us/library/y2ky8xsk.aspx
I have read many fine algorithms for identifying the most significant bit for 32- and 64-bit integers (including other posts here on SO). But I am using BigIntegers, and will be dealing with numbers up to 4000 bits long. (The BigInteger will hold the Hilbert index into the Hilbert space-filling curve that meanders through a 1000-dimension hypercube at a fractal depth of 4.) But the bulk of the cases will involve numbers that could fit inside a 64 bit integer, so I want a solution that is optimal for the common cases but can handle the extreme cases.
The naive way is:
BigInteger n = 234762348763498247634;
int count = 0;
while (n > 0) {
n >>= 1;
count++;
}
I was thinking of converting common cases to Longs and using a 64-bit algorithm on those, otherwise using a different algorithm for the really big numbers. But I am not sure how expensive the conversion to a Long is, and whether that will swamp the efficiencies of doing the remainder of the computation on a 64-bit quantity. Any thoughts?
One intended use for this function is to help optimize inverse gray code calculations.
Update. I coded two approaches and ran a benchmark.
If the number was under Ulong.MaxValue, then converting to a Ulong and doing the binary search approach was twice as fast as using BigInteger.Log.
If the number was very large (I went as high as 10000 bits), then Log was 3.5 times faster.
96 msec elapsed for one million calls to MostSignificantBitUsingLog
(convertable to Long).
42 msec elapsed for one million calls to
MostSignificantBitUsingBinarySearch (convertable to Long).
74 msec elapsed for ten thousand calls to MostSignificantBitUsingLog
(too big to convert).
267 msec elapsed for ten thousand calls to
MostSignificantBitUsingBinarySearch (too big to convert).
Here is the code for using Log:
public static int MostSignificantBitUsingLog(BigInteger i)
{
int bit;
if (i == 0)
bit = -1;
else
bit = (int)BigInteger.Log(i, 2.0);
return bit;
}
Here is my approach to binary search. It could be improved to extend the binary division up into the BigInteger range. I will try that next.
public static int MostSignificantBitUsingBinarySearch(BigInteger i)
{
int bit;
if (i.IsZero)
bit = -1;
else if (i < ulong.MaxValue)
{
ulong y = (ulong)i;
ulong s;
bit = 0;
s = y >> 32;
if (s != 0)
{
bit = 32;
y = s;
}
s = y >> 16;
if (s != 0)
{
bit += 16;
y = s;
}
s = y >> 8;
if (s != 0)
{
bit += 8;
y = s;
}
s = y >> 4;
if (s != 0)
{
bit += 4;
y = s;
}
s = y >> 2;
if (s != 0)
{
bit += 2;
y = s;
}
s = y >> 1;
if (s != 0)
bit++;
}
else
return 64 + MostSignificantBitUsingBinarySearch(i >> 64);
return bit;
}
Update 2: I changed my binary search algorithm to work against BigIntegers up to one million binary digits and not call itself recursively in 64 bit chunks. Much better. Now it takes 18 msec to run my test, and is four times faster than calling Log! (In the code below, MSB is my ulong function that does the same sort of thing, with the loop unrolled.)
public static int MostSignificantBitUsingBinarySearch(BigInteger i)
{
int bit;
if (i.IsZero)
bit = -1;
else if (i < ulong.MaxValue)
bit = MSB((ulong)i);
else
{
bit = 0;
int shift = 1 << 20; // Accommodate up to One million bits.
BigInteger remainder;
while (shift > 0)
{
remainder = i >> shift;
if (remainder != 0)
{
bit += shift;
i = remainder;
}
shift >>= 1;
}
}
return bit;
}
You can calculate the log2 which represent the number of bits needed:
var numBits = (int)Math.Ceil(bigInt.Log(2));
You can treat it like a binary-search problem.
You have an upper limit of 4000 (add some room maybe)
int m = (lo + hi) / 2;
BigInteger x = BigInteger(1) << m;
if (x > n) ...
else ...
In .Net 5 this is now built-in...
int log2 = myBigInt.GetBitLength()
If you can use Java rather than C#, there is a library for arbitrary precision Hilbert curve indexing that you can find at http://uzaygezen.googlecode.com. For the implementation of the gray code inverse, you may want to have a closer look at LongArrayBitVector.grayCodeInverse or perhaps BitSetBackedVector.grayCodeInverse in the mentioned project.
8 years late, to find the MSB top bit (aka Log2) I came up with this quick method...
static int GetTopBit(BigInteger value)
{
if (value < 0)
BigInteger.Negate(value);
int lowerBytes = value.GetByteCount(true) - 1;
int t = value.ToByteArray(true)[lowerBytes];
int top = t > 127 ? 8 : t > 63 ? 7 : t > 31 ? 6 : t > 15 ? 5 : t > 7 ? 4 : t > 3 ? 3 : t > 1 ? 2 : 1;
int topbit = (top + lowerBytes * 8);
return topbit;
}