The code below takes a BigInteger n and finds a number less than n that is also a power of 2. It works fine with small numbers but the first branch of the if statement does not work for int.MaxValue and above. Apparently subtracting 1 (BigInteger.Log(n - 1)) is not enough for larger numbers.
How can I calculate a number to subtract that is large enough to make a difference and yet work on smaller numbers too?
public BigInteger FindNearestPowerOfTwo (BigInteger n)
{
double number = 0;
BigInteger big = 0;
if (n.IsPowerOfTwo)
{
number = BigInteger.Log(n - 1) / BigInteger.Log(2);
}
else
{
number = BigInteger.Log(n) / BigInteger.Log(2);
}
number = Math.Floor(number);
big = BigInteger.Pow(2, (int) number);
return (big);
}
In the
ifbranch, you can subtract something from the quotient,for example (I’d be careful with subtracting 1.0 there since
BigInteger.Log(x)isn’t exact, the quotient could be a little too small, then subtracting 1.0 would give you the wrong power of 2). That works also for pretty large numbers (but adoublehas only 53 bits of precision, so for numbers larger than 2^(2^54) that is guaranteed to fail – however, that’s a lot more memory than currently available).But easier would of course be
However, the
elsebranch is problematic. Ifnis very close to a power of 2,can be a little too large or too small, moving the quotient across the closest integer to the exact result. You should check that
bigis indeed smaller thannand if not, divide by 2.It may be that
BigInteger.Log(n, 2.0)produces more exact results than dividing two natural logarithms. (I don’t know the implementation.)