Разные операции упрощения в Ruby

#ruby #loops #while-loop

#ruby #циклы #цикл while

Вопрос:

Я пытался написать программу о другом операторе упрощения в Ruby. Я должен находить числа (ab / bc) = a / c , когда a, b, c являются цифрами, а bc> ab. Например: 16 / 64 = 1 / 4 .

Вот мой код :

 a = 1
b = 1
c = 1 
num1 = 10*a   b
num2 = 10*b   c

while b < 9 amp;amp; c < 9
  b  = 1
  num1  = 1
  num2 = num2   10 
  while num2 > num1
    c  =1 
    num2  = 1
    while a < 9 
      a  = 1
      num1 = num1   10
      if (num1 / num2) == (a / c)
        puts "#{a} / #{b}"
      end
   end
end
end
 

Я должен достичь 16/64, 19/95, 26/65 и 49/98, но вместо этого Ruby дает мне 2/2, 3/2, 5/2, 7/2 и 9/2. Что не так с моим кодом? Мне разрешено делать это только с помощью цикла while. Итак, никаких других методов.

Комментарии:

1. кстати, я не могу использовать строковые переменные.

2. Откуда берется 10*a b / 10*b c ?

3. Я определяю его как ab / bc. Когда он разделяется, если ответ равен a / c , я должен получить результат: ab / bc .

4. Можете ли вы привести пример для a , b и c где ab / bc не равно a / c ?

5. в то время как a = 1 b = 2 c = 1 ab / bc = 12/21, если упростить: 4/7. В этом примере 12/21 не равно 1/1 . Но если a = 2 b = 6 c = 5, ab / bc = 26/65, упрощается на 2/5. Он также равен a / c, который равен 2/5.

Ответ №1:

Вот как я бы это написал:

 (1..9).each do |a|
  (1..9).each do |b|
    (1..9).each do |c|
      ab = 10*a   b
      bc = 10*b   c
      next if bc <= ab || (ab.to_f / bc) != (a.to_f / c)

      puts "#{ab} / #{bc} == #{a} / #{c}"
    end
  end
end

# Result:
# 16 / 64 == 1 / 4
# 19 / 95 == 1 / 5
# 26 / 65 == 2 / 5
# 49 / 98 == 4 / 8
 

Обратите внимание на мое использование to_f — что важно, потому что, если вы просто попытаетесь разделить целые числа, вы получите целочисленный ответ (например 3/2 == 1 , но 3.to_f/2 == 1.5 ).


Что не так с вашим решением? Помимо вышеупомянутой проблемы с целочисленным делением (именно поэтому ваши результаты явно неверны), есть несколько проблем.

Во-первых, вы немедленно увеличиваете значения a b и c в циклах, поэтому вы никогда не проверяете случаи, когда они равны 1. (Вот почему все ваши результаты начинаются с b == 2 .)

Кроме того, этот внутренний цикл глючит:

 while a < 9 
  a  = 1
  # ...
 

…потому что, изменив значение a , вы также, возможно, сделали недействительным предположение, что num2 > num1 . (Вот почему ваши результаты содержат неправильные дроби.)

Далее, ваша общая стратегия использования while циклов ошибочна: вы никогда не устанавливаете c или a не возвращаетесь к 1 — так что вам фактически не удается перебрать большинство возможных значений для (a, b, c) . (Вот почему большинство правильных ответов отсутствуют.)

… И вдобавок ко всему, вы печатаете не то, что нужно!! Вопрос заключался в том, чтобы найти все числа, где ab / bc == a / c , но вы печатаете a / b — так что, конечно, это будет неправильно 😅


Мораль истории: узнайте, как использовать отладчик, тщательно подумайте о том, какой логический поток вы написали, и, возможно, попробуйте создать из более простого базового варианта (например, исправить a == 1 ), прежде чем расширять всю логику 😀

Комментарии:

1. Кстати, я предполагаю a, b, c != 0 , и вы не хотели включать глупые результаты, такие как: 10 / 0 == 1 / 0 .

2. Большое вам спасибо за ваш ответ, но это мое домашнее задание для школы, и мы не изучаем такие методы, как next или .each. Вот почему я борюсь. Мне разрешено делать это только с помощью if и while . Вы правы насчет моего кода, он полон ошибок, но я новичок и стараюсь учиться :)))

3. Проблема вполне решаема с помощью while , но вы можете найти это немного сложнее… Тем не менее, надеюсь, мои комментарии выше должны указать на некоторые проблемы с вашей первой попыткой!

4. …Хотя, как бы то ни было, если ваш учитель явно не попросил вас использовать только while циклы (??!!), Вы не должны чувствовать себя обязанным придерживаться такого крошечного подмножества языка!

5. ab.to_f / bc могут быть переписаны как ab.fdiv(bc) . И есть даже вариант «без потерь»: ab.quo(bc)

Ответ №2:

Ваша логика очень сложная, поэтому мне довольно сложно следовать. На самом деле, я вообще этого не понимаю.

Я заметил пару вещей, которые могут или не могут объяснить ваши проблемы.

Вы инициализируете все три цифры равными 1, а затем немедленно увеличиваете их в начале цикла. Это означает, что вы никогда не получите никаких решений, которые включают 1, например, 16/64 = 1/4. Либо инициализируйте переменные равными 0, либо переместите приращение в конец цикла. (В любом случае, убедитесь, что вы не испортили условия выхода таким образом!)

Кроме того, вы более или менее увеличиваете их все одновременно в одном цикле, тогда как на самом деле вам нужны три вложенные итерации, в которых вы пытаетесь (1, 1, 1), (1, 1, 2), (1, 1, 3), и так далее, вместо того, чтобы(1, 1, 1), (2, 2, 2), (3, 3, 3), …

Вы используете целочисленное деление во всем своем коде. Но при целочисленном делении, например, 12/23 == 0 и 1/3 == 0 , следовательно 12/23 == 1/3 , и, таким образом, будет считаться допустимым решением. Лично я бы вместо этого использовал рациональные числа.

Кроме того, это выглядит подозрительно : b < 9 amp;amp; b < 9 .

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

 a = 0

while (a  = 1) < 10
  b = 0

  while (b  = 1) < 10
    c = 0

    while (c  = 1) < 10
      r = Rational(10*a   b, 10*b   c)
      puts "#{a}#{b}/#{b}#{c} = #{a}/#{c} = #{r}" if r < 1 amp;amp; r == Rational(a, c)
    end
  end
end
 

Лично я бы написал что-то вроде этого:

 DIGITS = (1..9).to_a.freeze

results = DIGITS.repeated_permutation(3).
  select do |a, b, c|
    r = Rational(10*a   b, 10*b   c)
    r < 1 amp;amp; r == Rational(a, c)
  end.
  map {|a, b, c| %W[#{a}#{b}/#{b}#{c} #{a}/#{c} #{Rational(a, c)}].join(' = ') }

puts results
# 16/64 = 1/4 = 1/4
# 19/95 = 1/5 = 1/5
# 26/65 = 2/5 = 2/5
# 49/98 = 4/8 = 1/2
 

Комментарии:

1. Спасибо за ваш ответ. На самом деле, я не могу решить, как я могу увеличивать цифры, просто используя while-loop. Ваш код короткий и эффективный, но я действительно не знаю методов. Я должен сделать это с помощью цикла while и if . Кстати, часть b < 9 amp;amp; b < 9 ускользнула от моего внимания, извините. Где я должен использовать цифры для их пошагового увеличения?

Ответ №3:

Решение можно упростить и сделать более эффективным, перевернув проблему с ног на голову, перебирая значения a/c , а не значения ab/bc .

Сначала обратите внимание, что когда ab/bc = a/c , bc > ab если и только если c > a . Поэтому мы можем написать следующее.

 (1..8).each do |a|
  (a 1..9).each do |c|
    r = Rational(a,c)
    (1..9).each do |b|
      num, denom = 10*a   b, 10*b   c
      puts "#{num}/#{denom} = #{a}/#{c}" if Rational(num, denom) == r
    end
  end
end
 

который отображает

 16/64 = 1/4
19/95 = 1/5
26/65 = 2/5
49/98 = 4/8