On 8/7/06, Daniel Schierbeck <daniel.schierbeck / gmail.com> wrote:
> Rick DeNatale wrote:
> > On 8/7/06, Daniel Schierbeck <daniel.schierbeck / gmail.com> wrote:
> >> Ch Skilbeck wrote:
> >> > 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
> >>
> >> Your question has already been answered by Simon, but I'd like to show
> >> you how your code could be more Rubyesque.
> >>
> >> First off, method name are always lower_case_with_underscore, so
> >>
> >>    def next_power_of_2(n)
> >>
> >> Ruby has the `unless' keyword, so
> >>
> >>    raise "integer please" unless n.kind_of? Integer
> >>
> >> but you don't really have to check the argument's class -- just check if
> >> the provided object responds to #to_int, or don't even check at all.
> >>
> >>    raise "integer please" unless n.respond_to? :to_int
> >>    n = n.to_int
> >>
> >> Parallel assignment is cool
> >>
> >>    high, count = 0, 0
> >>
> >> I'd split the next part up, but that may just be me
> >>
> >>    (0..(n.size * 8 - 2)).each do |b|
> >>      count += n[b]
> >>      high = b unless n[b] == 0
> >>    end
> >>
> >> Just some thoughts
> >
> > Here's another take
> >
> > irb(main):016:0> class Fixnum
> > irb(main):017:1>     def next_power_of_2
> > irb(main):018:2>       trial = 1
> > irb(main):019:2>       trial <<= 1 while trial < self
> > irb(main):020:2>       return trial
> > irb(main):021:2>     end
> > irb(main):022:1> end
> > => nil
> > irb(main):023:0> (-1..10).collect { | i | [i, i.next_power_of_2] }
> > => [[-1, 1], [0, 1], [1, 1], [2, 2], [3, 4], [4, 4], [5, 8], [6, 8],
> > [7, 8], [8, 8], [9, 16], [10, 16]]
> > irb(main):024:0>
> >
> > This should be fairly fast since at first glance it's o(log2(n))
> >
> > And it makes it a method of Fixnum
> >
>
> Very nice. Better add it to Integer instead, though -- otherwise Bignums
> won't have the method.

Fair enough, and while I'm at it why not handle Floats as well

class Integer
        def next_power_of_2
                trial = 1
                loop do
                        return trial if trial >= self
                        trial <<= 1
                end
        end
end

class Float
        # Defer to Fixnum if not >= 0,0 and < 1.0
        def next_power_of_2


                ciel.next_power_of_2 if self >= 1 || self < 0

                last_trial = 1.0
                loop do
                        trial = last_trial / 2.0
                        raise
ArgumentError.new("#{self}.next_power_of_2 is not representable") if
trial.zero?
                        return last_trial if trial < self
                        last_trial = trial
                end
        end
end


Note that some of the printed representations of some of those values
of 2^n for negative n might look weird, but that's floating point math
for you

=> 3.814697265625e-06
irb(main):016:0> t = 0.00003.next_power_of_2
=> 3.0517578125e-05
irb(main):017:0> while t < 1.0
irb(main):018:1>    p t
irb(main):019:1>    t *= 2.0
irb(main):020:1> end
3.0517578125e-05
6.103515625e-05
0.0001220703125
0.000244140625
0.00048828125
0.0009765625
0.001953125
0.00390625
0.0078125
0.015625
0.03125
0.0625
0.125
0.25
0.5
=> nil


-- 
Rick DeNatale