In my attempt to learn Ruby out in the open, here’s my solution for Project Euler Problem 44

So much for my brute-force-only-just-get-the-answer-in-less-than-one-minute approach. I worked through this problem four different ways — each time holding x number of pentagonal numbers in a various data structure for quick comparison. That was a bad move as each attempt took forever to complete. Instead I tried calculating each pentagonal on the fly and Wikipedia clued me into the pentagonal? check. Premature optimization. Still bad most of the time.

Other than the newly discovered math, there are a few bits I’d like to point out. There’s the natural number check found within the pentagonal? method and I guess there’s no concept of Integer::Max in Ruby so I stole someone else’s implementation. Should I be surprised that Integer::Max doesn’t exist?

As always, any feedback is welcome.

# Euler 44
# http://projecteuler.net/index.php?section=problems&id=44
# Pentagonal numbers are generated by the formula,
# Pn=n(3n1)/2. The first ten pentagonal numbers are:
#
# 1, 5, 12, 22, 35, 51, 70, 92, 117, 145, ...
#
# It can be seen that P4 + P7 = 22 + 70 = 92 = P8. However,
# their difference, 70 - 22 = 48, is not pentagonal.
#
# Find the pair of pentagonal numbers, Pj and Pk, for which
# their sum and difference is pentagonal and D = |Pk - Pj|
# is minimised; what is the value of D?
timer_start = Time.now

class Integer
  def pentagonal
    return self*(3*self-1)/2
  end

  # http://en.wikipedia.org/wiki/Pentagonal_number
  # If n is a natural number, then x is the nth pentagonal
  # number. If result is not a natural number,
  # then self is not pentagonal.
  def pentagonal?
    return ((Math.sqrt(24*self + 1) + 1) / 6) % 1.0 == 0.0;
  end

  # http://drawohara.com/post/117643208/
  # ruby-integer-max-and-integer-min
  N_BYTES = [42].pack('i').size
  N_BITS = N_BYTES * 8
  MAX = 2 ** (N_BITS - 2) - 1
  MIN = -MAX - 1
end

# Another upper bound guess
upper_bound = 5000
answer = Integer::MAX

1.upto(upper_bound) do |j|
  (j+1).upto(upper_bound) do |k|
    pk, pj = k.pentagonal, j.pentagonal
    d = pk - pj

    break if d > answer
    next if !d.pentagonal?

    s = pj + pk
    if s.pentagonal? then
      answer = d
    end
  end
end

puts answer
puts "Elapsed Time: #{(Time.now - timer_start)*1000} milliseconds"

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>