Can someone tell me if there’s a better way to do this? It takes a
number and returns the next power of 2 up (or the original if it was
already a power of 2) Specifically, are there features of Ruby that I
should be using in this case?
Cheers,
Charlie.
def nextPowerOf2(n)
raise “integer please” if !n.kind_of? Integer
high = 0
count = 0
(0…n.size * 8 - 2).each {|b| count += n[b] ; high = b if n[b] != 0}
1 << high + (count > 1 ? 1 : 0)
end
Can someone tell me if there’s a better way to do this? It takes a
number and returns the next power of 2 up (or the original if it was
already a power of 2) Specifically, are there features of Ruby that I
should be using in this case?
you how your code could be more Rubyesque.
the provided object responds to #to_int, or don’t even check at all.
(0…(n.size * 8 - 2)).each do |b|
count += n[b]
high = b unless n[b] == 0
end
Can someone tell me if there’s a better way to do this? It takes a
number and returns the next power of 2 up (or the original if it was
already a power of 2) Specifically, are there features of Ruby that I
should be using in this case?
Others have already given you floating point solutions to this, but
I’ve found that at least for numbers under 2**64, this is faster (uses
only integer arithmetic). This method is also easily translateable
into extremely fast C, if that becomes necessary:
def nextPowerOf2(n)
return n if (n-1)&n == 0
pow=1
while (n >= 0x100000000) do pow += 32; n >>= 32; end
if (n & 0xFFFF0000 > 0) then pow += 16; n >>= 16; end
if (n & 0xFF00 > 0) then pow += 8; n >>= 8; end
if (n & 0xF0 > 0) then pow += 4; n >>= 4; end
if (n & 0xC > 0) then pow += 2; n >>= 2; end
if (n & 0x2 > 0) then pow += 1; n >>= 1; end
1<<pow
end
It returns “0” when handed 0, when arguably it should return 1; on the
other hand, the log-based methods simply blow up when handed 0, so
this is an improvement.
Benchmark on the Math.log method, the originally posted code, and then
my code shows:
This should be fairly fast since at first glance it’s o(log2(n))
When the alternatives are O(1), that’s not that great!
Except that the implementation of Math.log itself is most likely
O(log2(n)) as well (unless the C source contains a gigantic lookup
table; unlikely). So using a strict O-based analysis, neither is
preferable over the other.
Whether the Math.log based solutions are faster is highly variable.
The Math.log solutions will have the speed of a C implementation on
their side (vs. an in-Ruby loop). But they need to calculate two
logs (this can be eliminated by caching the result of Math.log(2) in a
constant), and then perform a division. But as Daniel M.
demonstrates, bypassing the Math.log(2) implementation with custom
in-Ruby code allows us to specific loop unrolling and other such
optimizations.
I hope that this doesn’t offend anyone, but in the spirit of test
infection…
I actually took the various suggestions and wrote test cases. Here’s
my file “next_power_of_2.r b” which defines either methods on Integer,
or a class with a next_power_of_2() class method, following the
various suggestions, I did give these methods a consistent name
following Ruby naming standards.
…
This really isn’t surprising, since floating point arithmetic only
approximates real arithmetic using real numbers.
My original intention was to benchmark the various suggestions, but
since you can get the wrong answers with arbitrarily fast code, I
don’t think that it matters much.
Hmm, what about:
def next_power_of_2(n)
throw ‘eeek’ if n < 0
return 1 if n < 2
1 << (n-1).to_s(2).size
end
Others have already given you floating point solutions to this, but
I’ve found that at least for numbers under 2**64, this is faster (uses
only integer arithmetic). This method is also easily translateable
into extremely fast C, if that becomes necessary:
(code snipped)
I should note that the algorithm I used - which could, I suppose, be
viewed as simply clever loop unrolling after doing quick 32-bit shifts
to get into the ballpark, was cribbed from some assembly in the C
header file longlong.h, which includes the macro count_leading_zeros
that counts the number of zeros in the front of a long long variable.
Any C implementation would probably be advised to make good use of
that macro, which may, depending on your processor, be implemented as
a single assembly language instruction. (See the BSR instruction on
x86, for example)
Also, since someone was saying that all the integer math
implementations were essentially equivalent in speed, being all
O(log(n)), here’s a O(log(log(n))) implementation. I shudder to think
though how big an input you’d need before this beats my earlier code:
def nextPowerOf2(n)
return n if (n-1)&n == 0
return 1 if n < 2
n <<= 1
t = [2]
t.unshift(t[0]*t[0]) while t[0] < n
t.shift
ret = 1
t.each {|s|
if (s <= n) then
ret *= s
n /= s
end
}
ret
end