require 'bigdecimal'


sqrt2 = Object.new
def sqrt2.a(n); n == 1? 1: 2; end
def sqrt2.b(n); 1; end


napier = Object.new
def napier.a(n); n == 1? 2: n - 1; end
def napier.b(n); n == 1? 1: n - 1; end

pi = Object.new
def pi.a(n); n == 1? 3: 6; end
def pi.b(n); (2*n - 1)**2; end




def estimate(cfrac, prec)
  last_result = nil
  terms = prec

  loop do
    
    result = cfrac.a(terms)
    (terms - 1).downto(1) do |n|
      a = BigDecimal cfrac.a(n)
      b = BigDecimal cfrac.b(n)
      digits = [b.div(result, 1).exponent + prec, 1].max
      result = a + b.div(result, digits)
    end
    result = result.round(prec)

    if result == last_result
      return result
    else
      
      last_result = result
      terms *= 2
    end
  end
end

puts estimate(sqrt2, 50).to_s('F')
puts estimate(napier, 50).to_s('F')
puts estimate(pi, 10).to_s('F')