2015-07-22 3 views
0

У меня есть этот код, чтобы вернуть true если num это сила 2.Создайте метод, чтобы узнать, является ли число силой 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) 

Я получаю сообщение об ошибке, хотя. Как я могу исправить и упростить этот код?

+0

Почему вы не используете функцию log2?Должен дать вам целое число, если вход находится на^2. Google '' 'log2 1024''' – urban

+0

Не специалист по Ruby, но кажется, что вы используете метод инъекции для целого числа вместо массива – Dleep

+0

Я попытался преобразовать num в массив с помощью' num.to_a', но это не сработает для меня – Shawn

ответ

5

Очевидно, что n является неотрицательным целым числом.

код

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

Примеры

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

Объяснение

Fixnum#to_s обеспечивает строковое представление целого числа (приемник) для данной базы. Аргумент метода, который по умолчанию равен 10, является базой. Например:

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

Это база 2, нас интересует.Для степеней 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" 

В течение нескольких натуральных чисел, которые не являются степенями 2:

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

Поэтому мы хотим, чтобы соответствовать двоичные строки, содержащие один 1.

Другой способ

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 

И один на дороге

Это использует Fixnum#bit_length и 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 
+0

Это классное решение! –

+0

Не могли бы вы дать более глубокое понимание синтаксиса этого ответа? Я не понимаю это несчастливо – Shawn

+0

Шон, пожалуйста, см. Мое редактирование. –

0

Как было указано в комментариях выше, вы получали ошибки, потому что пытаетесь использовать метод inject для non-iterable (int). Вот решение, используя предложенного log2

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

Примечание: проваливается с очень большими числами, близкими к бинарным файлам (например, 2^64 - 1). Простой вариант (но медленнее):

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

Просьба прокомментировать любые улучшения, которые могут возникнуть у любого из вас.

+0

Конечно, мы никогда не используем 'conditional_statement? true: false', потому что 'conditional_statement' по определению будет оцениваться как' true' или 'false'. – vgoff

+0

Да, я играл в это безопасно и использовал код OP как базу, так как это моя первая попытка Ruby. Затем понял, насколько бессмысленно это «если». – Dleep

+0

Не стесняйтесь обновлять свой код, чтобы улучшить его. Поэтому он не упоминается снова, или кому-то другому не нужно его редактировать. :) И добро пожаловать в Руби! – vgoff

4

Try:

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

Это хорошо объясняется here (для C#, но @ объяснение GregHewgill в тоже применимо)

1

Я хотел бы сделать что-то вроде этого, используя Math модуль в Ruby.

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

Или, если вы хотите быть действительно круто:

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

Некоторые IRB выход:

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 

Этот метод предполагает, что вход является положительным целым числом.

Source

+1

'(Math.log2 (n)% 1) .zero? ' – vgoff

+0

Это тоже довольно законно - добавит ответа. –

+0

'power_of_two? -3 # => Math :: DomainError: числовой аргумент вне домена - «log2» '. –

0

Вот еще одно решение, которое использует рекурсию:

def power_of_2?(number) 
return true if number == 1 
return false if number == 0 || number % 2 != 0 
power_of_2?(number/2) 
end 
0

На мой взгляд, самый простой - но, возможно, немного долго - способ делать то, что вам нужно сделать, это просто пишу этот рекурсивный метод следующим образом:

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 

Одним из них является сила два (2^0), поэтому он сначала проверяет, является ли указанное число равным 1. Если нет, оно проверяет, является ли оно нечетным, потому что 1 является единственным нечетным числом, которое является степенью двух.

Если он нечетный, он возвращает false и переходит к инструкции else. Он будет проверять, является ли число, деленное на 2, равным двум, потому что тогда это, очевидно, было бы силой 2. Оно делает это как поплавок, потому что 5/2 в Ruby вернется 2.

Если это неверно, затем снова проверяет, является ли число нечетным - ненужным в первом раунде, необходимым после этого. Если число нечетное, оно будет делить число на два, а затем сделать цикл в другое время.

Это будет продолжаться до тех пор, пока программа не решит себя, получив 2 или любое нечетное число и вернет true или false соответственно.

0

Я столкнулся с этим в предпродажной подготовке к bootcamp. Я не математик и не понимаю некоторых из этих методов, поэтому я хотел представить здравый смысл для таких людей, как я. это требует небольшого знания математики, за исключением того, что знать число со второй силой будет результатом некоторого числа, умноженного на себя.

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

этот метод подсчитывает к переменному NUM, начиная с 1, и возвращает истину, если (любое из этих чисел в последовательности, умноженной на себе) равно NUM &, если Num не равен 0 (об этом ниже) ,

пример: Num = 9

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

верно возвращается и способ завершения выполнения.

Метод #times требует целого числа> 0, поэтому этот случай края «обрабатывается» из-за того, что #times ничего не делает с «0» в качестве переменной и возвращает false, если вне итерации #times.

+0

, хотя сначала это выглядело мне элегантно, теперь я понимаю, что он неэффективен, поскольку все выходят, поскольку он проходит через потенциально намного больше чисел, чем нужно для получения вашего ответа. выглядел хорошо. – brocknroll

Смежные вопросы