Reputation: 147
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
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
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
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