elixir
elixir

Reputation: 147

Different Simplifaction Operation in Ruby

I tried to write a program about a different simplification operator in Ruby. I have to find numbers (ab / bc) = a / c when a, b, c are digits and bc > ab. For example: 16 / 64 = 1 / 4.

Here's my code :

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

while b < 9 && 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

I should reach 16/64, 19/95, 26/65 and 49/98 but instead, Ruby gives me 2/2, 3/2, 5/2, 7/2 and 9/2. What's wrong with my Code? I'm only allowed to do this with while loop. So, no other methods.

Upvotes: 0

Views: 134

Answers (3)

Cary Swoveland
Cary Swoveland

Reputation: 110675

The solution can be simplified and made more efficient by turning the problem on its head, looping through values of a/c rather than those of ab/bc.

First observe that when ab/bc = a/c, bc > ab if and only if c > a. We therefore may write the following.

(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

which displays

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

Upvotes: 0

Tom Lord
Tom Lord

Reputation: 28305

Here's how I would have written it:

(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

Note my use of to_f - which is important because if you just try to divide integers, you get an integer answer (e.g. 3/2 == 1, but 3.to_f/2 == 1.5).


What's wrong with your solution? Well aside from the aforementioned integer division issue (which is why your results are clearly incorrect), there are a few problems.

For one thing, you're immediately incrementing the values of a, b and c in the loops, so you never actually test for cases where they are equal to 1. (This is why all your results start with b == 2.)

Also, this inner loop is buggy:

while a < 9 
  a += 1
  # ...

...because by changing the value of a, you also may have invalidated the assumption that num2 > num1. (This is why your results contain improper fractions.)

Next, your overall strategy of using while loops is flawed: You're never setting c or a back to 1 -- so you're actually failing to loop over the majority of possible values for (a, b, c). (This is why most valid answers are missing.)

...And on top of that, you're printing the wrong thing!! The question was to find all numbers where ab / bc == a / c, but you're printing a / b - so of course it's going to be wrong 😅


Moral of the story: Learn how to use a debugger, think carefully about what logical flow you've written, and maybe try building up from a simpler base case (e.g. fix a == 1) before expanding into the whole logic 😀

Upvotes: 3

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369458

Your logic is very complex, so I find it quite hard to follow. In fact, I don't understand it at all.

There are a couple of things I noticed that may or may not explain your problems.

You are initializing all three digits to 1, then immediately increment them at the beginning of the loop. That means, you will never get any solutions that include 1, such as 16/64 = 1/4. Either initialize the variables to 0 or move the increment to the end of the loop. (Either way, make sure you don't screw up the exit conditions that way!)

Also, you are more or less incrementing all of them at the same time in a single loop, whereas you actually want three nested iterations where you try (1, 1, 1), (1, 1, 2), (1, 1, 3), and so on, instead of (1, 1, 1), (2, 2, 2), (3, 3, 3), …

You are using integer division throughout your code. But in integer division, for example, 12/23 == 0 and 1/3 == 0, therefore 12/23 == 1/3 and will thus be counted as a valid solution. Personally, I would use rational numbers instead.

Also, this looks fishy: b < 9 && b < 9.

Here is a solution that somewhat resembles yours. I tried to fix your code, but I just couldn't understand how it works, I am just not clever enough.

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 && r == Rational(a, c)
    end
  end
end

Personally, I would write something like this:

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 && 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

Upvotes: 2

Related Questions