2

I have this code to return true if num is a power of 2.

def is_power_of_two?(num)
  result = num.inject(0) {|n1, n2| n2 ** n1}
  if result == num
    true
  else
    false
  end
end

p is_power_of_two?(16)

I keep getting an error though. How could I fix and simplify this code?

S H
  • 161
  • 1
  • 10
  • Why don't you use log2 function? Should give you back integer if the input is on ^2. Google ```log2 1024``` – urban Jul 22 '15 at 21:25
  • Not a Ruby expert but it seems you're using the inject method on an integer instead of on an array – Dleep Jul 22 '15 at 21:26
  • I tried converting num to an array with `num.to_a` but that wouldnt work for me – S H Jul 22 '15 at 21:28
  • Log2 looks like a good idea, but how could I incorporate it to make sure I'm only getting whole integers as a result? – S H Jul 22 '15 at 21:29

9 Answers9

11

Clearly, n is a non-negative integer.

Code

def po2?(n)
  n.to_s(2).count('1') == 1
end

Examples

po2?  0     #=> false
po2?  1     #=> true
po2? 32     #=> true
po2? 33     #=> false

Explanation

Fixnum#to_s provides the string representation of an integer (the receiver) for a given base. The method's argument, which defaults to 10, is the base. For example:

16.to_s     #=> "16" 
16.to_s(8)  #=> "20" 
16.to_s(16) #=> "10"
15.to_s(16) #=>  "f"

It's base 2 we're interested in. For powers of 2:

 1.to_s(2)  #=>      "1" 
 2.to_s(2)  #=>     "10" 
 4.to_s(2)  #=>    "100" 
 8.to_s(2)  #=>   "1000"
16.to_s(2)  #=>  "10000"

For a few natural numbers that are are not powers of 2:

 3.to_s(2)  #=>    "11" 
 5.to_s(2)  #=>   "101" 
11.to_s(2)  #=>  "1011" 

We therefore wish to match binary strings that contain one 1.

Another Way

R = /
    \A      # match beginning of string ("anchor")
    10*     # match 1 followed by zero or more zeroes
    \z      # match end of string ("anchor")
    /x      # free-spacing regex definition mode

def po2?(n)
  (n.to_s(2) =~ R) ? true : false
end

po2?(4)  #=> true
po2?(5)  #=> false

One more

This uses Fixnum#bit_length and Fixnum#[]:

def po2?(n)
  m = n.bit_length-1
  n[m] == 1 and m.times.all? { |i| n[i].zero? }
end
po2?  0     #=> false
po2?  1     #=> true
po2? 32     #=> true
po2? 33     #=> false

And a fourth, perhaps the best

def po2?(n)
  return false if n <= 0
  while n.even?
    n /= 2
  end
  n == 1
end
po2?  0     #=> false
po2?  1     #=> true
po2? 32     #=> true
po2? 33     #=> false
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • Could you give some more insight into this answer's syntax? I don't understand it unfortuntely – S H Jul 23 '15 at 01:07
  • Cary, I believe there are no case where a negative number can be power of 2. A negative N will result in a number less than 1 and a positive non-zero N, will result in a number greater than 1. If N is a negative number, the use case is invalid and po2? should be false – E.A. Oct 20 '17 at 18:44
  • @EA, I wrote this more than two years ago. Looking back I'm wondering what I was thinking at the time, but also why it took so long for someone (you) to point out the obvious. Thanks for letting me know. I'll edit. – Cary Swoveland Oct 20 '17 at 23:42
5

Try:

def is_power_of_two?(num)
  num != 0 && (num & (num - 1)) == 0
end

It is well explained here (for C#, but @GregHewgill's explanation applies here as well)

Community
  • 1
  • 1
Mario Zannone
  • 2,843
  • 12
  • 18
3

I would do something like this, using Ruby's Math module.

def power_of_two?(n)
  Math.log2(n) % 1 == 0
end

Or, if you wanted to be really cool:

def power_of_two?(n)
  (Math.log2(n) % 1).zero?
end

Some IRB output:

2.1.0 :004 > power_of_two?(2)
 => true
2.1.0 :005 > power_of_two?(32768)
 => true
2.1.0 :006 > power_of_two?(65536)
 => true

This method assumes that the input is a positive integer.

Source

Jake Worth
  • 5,490
  • 1
  • 25
  • 35
2

Another way to solve this is to go the other way around than most of the answers here - we can use the number 1 to start and find out if the number is the power of two. Like this:

def power_of_two?(num)
  product = 1

  while product < num
    product *= 2
  end
  product == num
end

We start with 1. Then we multiply the 1 by 2, and keep multiplying by 2 until the product is larger than num (product < num). Once we hit that condition, we stop, exit the loop, and check if it's equal to num (product == num). If it is, the num is the power of 2.

Alek2077
  • 21
  • 4
0

As was pointed out in the comments above, you were getting errors because you're trying to use the inject method on a non-iterable (an int). Here's a solution using the suggested log2

def is_power_of_two?(num)
  result = Math.log2(num)
  result == Integer(result)
end

Note: will fail with very big numbers close to binaries (like 2 ^ 64 - 1). A foolproof version (but slower) would be:

def is_power_of_two?(num)
  while (num % 2 == 0 and num != 0)
    num /= 2
  end
  num == 1
end

Please comment any improvements that any of you may find.

Dleep
  • 1,045
  • 5
  • 12
  • Of course we never use `conditional_statement ? true : false` because `conditional_statement` by definition will itself evaluate as `true` or `false`. – vgoff Jul 22 '15 at 22:01
  • Yeah i was playing it safe and using OP's code as a base since it's my very first attempt at Ruby. Then realized how pointless that `if` was. – Dleep Jul 22 '15 at 22:16
  • Feel free to update your code to improve that. So it doesn't get mentioned again, or so someone else doesn't have to edit it. :) And welcome to Ruby! – vgoff Jul 23 '15 at 08:44
  • Not a code review site, of course, but at this point, I wouldn't even use the local variable result. Just compare the two values directly, and it will return true or false, and is simple enough to read and understand. – vgoff Jul 23 '15 at 21:09
  • @vgoff you should come check us out over at CR, maybe drop by [The Second Monitor](http://chat.stackexchange.com/rooms/8595/the-2nd-monitor) – Malachi Jul 23 '15 at 21:15
0

Here is another solution that uses recursion:

def power_of_2?(number)
 return true if number == 1
 return false if number == 0 || number % 2 != 0
 power_of_2?(number / 2)
end
K M Rakibul Islam
  • 33,760
  • 12
  • 89
  • 110
0

In my opinion, the easiest -- but maybe a little long -- way of doing what you need to do is just writing this recursive method like so:

def power_of_two?(number)
    continue = true
    if number == 1
        return true
    end
    if number % 2 != 0
        return false
    else
        while continue == true do
            if number.to_f / 2.0 == 2.0
                continue = false
                return true
            else
                if number % 2 != 0
                    continue = false 
                    return false
                else
                    number /= 2
                    continue = true
                end
            end
        end
    end
end

One is a power of two (2^0), so it first checks if the number given is 1. If not, it checks if it is odd, because 1 is the only odd number that is a power of two.

If it is odd it returns false and moves on to the else statement. It will check if the number divided by 2 is two, because then it would obviously be a power of 2. It does this as a float, because 5/2 in Ruby would return 2.

If that is false, it then again checks if the number is odd -- unnecessary on the first round, necessary after that. If the number is not odd, it will divide the number by two and then do the loop another time.

This will continue until the program resolves itself by getting 2 or any odd number, and returns true or false, respectively.

Charles
  • 1,384
  • 11
  • 18
0

I ran into this one in a bootcamp application prep. I'm not a math person and don't understand a few of these methods, so I wanted to submit a common sense approach for people like me. this requires little knowledge of math, except to know a number to the second power will be the result of some number multiplied by itself.

def is_power_of_two?(num)
  num.times  {|n| return true if (n+1) * (n+1) == num}
  false
end

this method counts up to the num variable starting at 1 and returns true if (any of those numbers in the sequence multiplied by itself) is equal to num & if num is not 0 (more on that below).

example: num = 9

1 * 1 == 9 #=> false
2 * 2 == 9 #=> false
3 * 3 == 9 #=> true 

true is returned and method is finished running.

the #times method requires an integer > 0, so this edge case is "handled" by virtue of the fact that #times does nothing with "0" as the variable and returns false when outside of the #times iteration.

brocknroll
  • 31
  • 8
  • while this looked elegant to me at first, I realize now that it's inefficient as all get out, as it goes through potentially a lot more numbers than needed to get your answer. looked good. – brocknroll Oct 10 '17 at 22:46
0
def power_of_two?(num)
  num.to_s(2).scan(/1/).length == 1
end
shilovk
  • 11,718
  • 17
  • 75
  • 74