Понимание Ruby логических операторов - PullRequest
0 голосов
/ 14 июня 2011

Я новичок в Ruby и подумал, что это отличный способ узнать больше, решив проблемы в Project Euler.

Вот то, что я придумал, используя грубую силу для Задачи 5:

#What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
end_point = 1_000_000_000 
start_point = 2_520
(start_point..end_point).each do |number|
  flag = true
  (2..20).each do |divisor|
    flag = flag & ( number % divisor ) == 0 ? true : false
    end
  print number.to_s + "\n" if flag
end

Это работает долго и не дает ответа.

Затем я использовал ту же логику, чтобы написать программу на C ++ для выполнения той же задачи:

#include<iostream>

using namespace std;

int main()
{
  unsigned long int solution = 2520;
  while(1)
  {
    bool flag = true;
    for(int divisor=2;divisor<=20;divisor++)
    {
      if( solution % divisor == 0)
        flag = flag & true;
      else{
        flag = false;
        break;
      }
    }
    if(flag == true){
      cout<<solution<<endl;
      break;
    }
    solution++;
  }
  return 0;
}

Это дает мне правильное решение и работает всего лишь секунду. Время выполнения на самом деле меня не касается, поскольку Ruby интерпретируется и компилируется в C ++, но неудача Ruby при возвращении правильного ответа меня удивляет. Я думаю, что это может быть из-за того, что я пытался написать стиль Ruby на C ++, а не на самом деле Ruby.

Что я здесь не так делаю?

Ответы [ 2 ]

3 голосов
/ 14 июня 2011

Я на самом деле решил эту проблему, не написав для нее программы. Это логика, которую я использовал:

Запишите все простые числа меньше 20 (цель).

[2, 3, 5, 7, 11, 13, 17, 19]

Для каждого простого числа поднимите его до максимальной мощности, для которой оно меньше целевого (20).

2**4 * 3**2 * 5 * 7 * 11 * 13 * 17 * 19

Для этого программно используйте алгоритм Сита Эратосфена - http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes для перебора простых чисел. Для каждого простого числа в списке найдите максимальную мощность, до которой оно увеличивается, чтобы получить число меньше целевого (20). Вы можете найти силу, используя эту формулу: (Math.log(target)/Math.log(i)).floor

Предполагая, что вы получите массив простых чисел: nums = [2, 3, 5, 7, 11, 13, 17, 19]

Тогда вы можете легко получить ответ, используя это:

nums.map {|i| i**((Math.log(target)/Math.log(i)).floor)}.inject(:*)
2 голосов
/ 14 июня 2011

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

Строка, в которой вы обновляете flag, является проблемой. Вы используете & (поразрядно-и), а не && (логически-и).

Среди других проблем, & имеет более высокий приоритет оператора, чем ==, поэтому ваша строка интерпретируется как (поскольку ? true : false избыточна):

flag = (flag & (number % divisor)) == 0

Теперь кажется, что true & some_integer - это true, что не == 0, поэтому flag всегда установлено на false.

Вместо этого вы хотите:

flag = flag && (number % divisor == 0)

или, более кратко и рубиново:

flag &&= number % divisor == 0

Альтернативное решение было бы сделать:

i = 1
while true
  break unless (2..20).any? {|d| i % d != 0}
  i+=1
end
puts i
...