In my attempt to learn Ruby out in the open, here’s my solution for Project Euler Problem 33.
I had to read this problem again and again before it started to make sense to me. Actually, I moved forward having to make a few assumptions. It appeared that trivial cases were cases where the numerator and denominator were both mod 10. Also, I assumed the number to be cancelled out could be in either the first or second position of the numerator. Maybe it’s just me, but I think this problem could have been written a little clearer.
After getting a decent grasp of the problem, it became a matter of working through how Ruby handles precision which is quite logical really. The only thing I learned about Ruby in this exercise was that next will move you to the next iteration point in ones loop. I guessed the keyword for this action would be continue but it didn’t take long to correct my mistake.
As always, any feedback is welcome.
# Euler 33
# http://projecteuler.net/index.php?section=problems&id=33
# The fraction 49/98 is a curious fraction, as an
# inexperienced mathematician in attempting to simplify it
# may incorrectly believe that 49/98 = 4/8, which is correct,
# is obtained by cancelling the 9s.
#
# We shall consider fractions like, 30/50 = 3/5, to be
# trivial examples.
#
# There are exactly four non-trivial examples of this type
# of fraction, less than one in value, and containing two
# digits in the numerator and denominator.
#
# If the product of these four fractions is given in its
# lowest common terms, find the value of the denominator.
timer_start = Time.now
numerator_product, denominator_product = 1, 1
(10..98).each do |n|
(n+1..99).each do |d|
# Non-trivial check
next if n % 10 == 0 && d & 10 == 0
# See if opposite digits in numerator and denominator match
if (n.to_s[0] == d.to_s[1] && n.to_s[1] < d.to_s[0])
# Second digit of numerator over first digit of denominator
fraction_as_float = Float(n.to_s[1]) / Float(d.to_s[0])
elsif (n.to_s[1] == d.to_s[0] && n.to_s[0] < d.to_s[1])
# First digit of numerator over second digit of denominator
fraction_as_float = Float(n.to_s[0]) / Float(d.to_s[1])
else
next
end
# Do we get the same value if we cancel out like digits?
if (Float(n) / Float(d) == fraction_as_float)
numerator_product*=n
denominator_product*=d
end
end
end
puts denominator_product / numerator_product
puts "Elapsed Time: #{(Time.now - timer_start)*1000} milliseconds"
Hmm, I took the problem a little more literally, and solved it by considering the number as (a*10+b)/(b*10+c)
solutions = [] 1.upto(9) do |a| 1.upto(9) do |b| 1.upto(9) do |c| x = a * 10 + b y = b * 10 + c solutions << [x,y] if (x*1.0 / y * 1.0 ) == ( a * 1.0 / c * 1.0) && x != y end end end product = solutions.inject([1,1]) {|a,c| [a[0] * c[0], a[1] * c[1]]} answer = product[1] while answer % product[0] == 0 do answer /= product[0] end puts answerI like what you put together. And I guess you proved that I could remove about half of my code if I really wanted to. Now you’re tightening up my code. Well done!
Even though I don’t actually need it to solve the problem, I should steal your while loop starting at line 14. I got lucky that my denominator_product / numerator_product was nice and cleanly divisible but it didn’t have to be.
I was flirting with converting to float by multiplying the values times 1.0 as well but then I found the giant F-bomb Float() converted and I just had to use it.
Thanks once again for the contribution.