def factorial_recursive(n)
  n.zero?? 1: n * factorial_recursive(n - 1)
end


def factorial_tail_recursive(n, prod = 1)
  n.zero?? prod: factorial_tail_recursive(n - 1, prod * n)
end


def factorial_iterative(n)
  (2...n).each { |i| n *= i }
  n.zero?? 1: n
end


def factorial_inject(n)
  (1..n).inject(1){ |prod, i| prod * i }
end


def factorial_reduce(n)
  (2..n).reduce(1,:*)
end


require 'benchmark'

n = 400
m = 10000

Benchmark.bm(16) do |b|
  b.report('recursive:')       {m.times {factorial_recursive(n)}}
  b.report('tail recursive:')  {m.times {factorial_tail_recursive(n)}}
  b.report('iterative:')       {m.times {factorial_iterative(n)}}
  b.report('inject:')          {m.times {factorial_inject(n)}}
  b.report('reduce:')          {m.times {factorial_reduce(n)}}
end