def leftrect(f, left, right)
  f.call(left)
end

def midrect(f, left, right)
  f.call((left+right)/2.0)
end

def rightrect(f, left, right)
  f.call(right)
end

def trapezium(f, left, right)
  (f.call(left) + f.call(right)) / 2.0
end

def simpson(f, left, right)
  (f.call(left) + 4*f.call((left+right)/2.0) + f.call(right)) / 6.0
end

def integrate(f, a, b, steps, method)
  delta = 1.0 * (b - a) / steps
  total = 0.0
  steps.times do |i|
    left = a + i*delta
    right = left + delta
    total += delta * send(method, f, left, right)
  end
  total
end

def square(x)
  x**2
end

def def_int(f, a, b)
  l = case f.to_s
      when /sin>/
        lambda {|x| -Math.cos(x)}
      when /square>/
        lambda {|x| (x**3)/3.0}
      end
  l.call(b) - l.call(a)
end

a = 0
b = Math::PI
steps = 10

for func in [method(:square), Math.method(:sin)]
  puts 
  actual = def_int(func, a, b)
  for method in [:leftrect, :midrect, :rightrect, :trapezium, :simpson]
    int = integrate(func, a, b, steps, method)
    diff = (int - actual) * 100.0 / actual
    printf , method, int, diff
  end
end