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"

2 Comments to “Project Euler 33: Ruby”

  1. Jon Bristow says:

    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 answer
  2. Ben Griswold says:

    I 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.

Leave a Reply

You can wrap your code with [ruby][/ruby] or [python][/python] blocks for syntax highlighting and you can use these traditional tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>