I'm new to Ruby, and as an exercise I implemented different factorial algorithms. Other rules are: raise an ArgumentError exception if n < 0 or n is not an integer.
I'm interested in whatever feedback you can think of, including Ruby idioms (can something be implemented more idiomatic?). If you see anything that can be improved in any way, let me know.
# While loop
def factorial_w(n)
validate(n)
total = 1
while n > 1
total *= n
n -= 1
end
total
end
# For loop
def factorial_f(n)
validate(n)
total = 1
for i in (2 .. n)
total *= i
end
total
end
# Recursive
def factorial_r_recursion(n)
if n < 2
1
else
n * factorial_r(n - 1)
end
end
def factorial_r(n)
validate(n)
factorial_r_recursion(n)
end
# Tail-recursive
def factorial_tr_recursion(n, acc)
if n < 2
acc
else
factorial_tr(n - 1, n * acc)
end
end
def factorial_tr(n, acc = 1)
validate(n)
factorial_tr_recursion(n, acc)
end
# Iterative with Range.each
def factorial_re(n)
validate(n)
if n == 0
1
else
(2 .. n - 1).each {|i| n *= i}
n
end
end
# Iterative with Range.inject
def factorial_ri(n)
validate(n)
(1 .. n).inject(:*) || 1 # || 1 handles n = 0 so !0 = 1
end
# Iterative with Range.reduce
def factorial_rr(n)
validate(n)
(1 .. n).reduce(:*) || 1 # || 1 handles n = 0 so !0 = 1
end
# Stirling's Approximation, will return infinity if n > 170
def factorial_sa(n)
validate(n)
Math.sqrt(2 * Math::PI * n) * (n / Math::E) ** n
end
# Helper for argument validation
def validate(n)
if n < 0 or not n.kind_of? Integer
raise ArgumentError, "n must be an integer and >= 0"
end
end