Skip to main content
1 of 3
NPN328
  • 761
  • 1
  • 10
  • 26

Different factorial algorithms

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 
NPN328
  • 761
  • 1
  • 10
  • 26