Why Can't This Code Find Powers? (Ruby)

2019-08-10 13:56发布

问题:

App Academy's practice test says their chosen way of finding if an input is a power of 2 is to keep dividing it by 2 on a loop and check whether the end result is 1 or 0 (after having tested for the numbers 1 and 0 as inputs), which makes sense, but why won't this way work?

def try
  gets(num)
  counter = 0
  go = 2 ** counter

  if num % go == 0 
    return true
  else
    counter = counter + 1
  end

    return false
end

I can't figure out why this won't work, unless the counter isn't working.

回答1:

There are a number of problems with your code.

  1. First of all, there is no loop and your counter will reset to zero each time if you intend to use the method in a loop, because of counter = 0.

  2. counter = 0; go = 2 ** counter basically means go = 2 ** 0 which is 1. Therefore num % 1 will always be 0

  3. You actually need to divide the number and change it in the process. 12 % 4 will return 0 but you don't know by that if 12 is a power of 2.

  4. IO#gets returns a string and takes a separator as an argument, so you need to use num = gets.to_i to actually get a number in the variable num. You are giving num to gets as an argument, this does not do what you want.

Try:

# Check if num is a power of 2
#
# @param num [Integer] number to check
# @return [Boolean] true if power of 2, false otherwise
def power_of_2(num)
  while num > 1 # runs as long as num is larger than 1
    return false if (num % 2) == 1 # if number is odd it's not a power of 2
    num /= 2 # divides num by 2 on each run
  end
  true # if num reached 1 without returning false, it's a power of 2
end


回答2:

I add some checks for your code. Note, that gets(num) returns a String. Your code is fine, but not for Ruby. Ruby hates type-cross-transform like Perl does.

def try(num = 0)
  # here we assure that num is number
  unless (num.is_a?(Integer)) 
    puts "oh!"
    return false
  end

  counter = 0
  go = 2 ** counter

  if num % go == 0 
    return true
  else
    counter = counter + 1
  end
    return false
end

The general problem is "how string could use '%' operator with number?"

Try some code in the interpretator (irb):

"5" % 2

or

"5" % 0