I was trying to make a recursive algorithm with Ruby and I couldn't do it so I kept popping the stack as it were and each time I tried a simpler recursive algorithm to see where my mistake was..
But I arrived at this:
def fact(n)
if n==0
1
else
fact(n)*fact(n-1)
end
end
puts fact(5)
and
ruby/part2.rb:81: stack level too deep (SystemStackError)
Ok what is going on?
Is it not possible to make recursive algorithms in Ruby??
your algorithm is incorrect, it should look like this
def fact(n)
if n==0
1
else
n*fact(n-1)
end
end
puts fact(5)
fact(n) * fact(n - 1) is infinite recursion. You need to reduce the problem size in each call.
def fact(n)
if n <= 0
1
else
n * fact(n - 1)
end
end
Or simply,
def fact(n)
n <= 0 ? 1 : n * fact(n - 1)
end
You have to do something like fact(n-1)*fact(n-2) because otherwise, fact(n),n=5 will be called forever.
Related
Can someone help me understand why the code below works fine
Works:
def factorial(n)
return 1 if n == 1
n * factorial(n-1)
end
puts factorial(5)
But when I refactor it like so, it throws an exception: *': nil can't be coerced into Integer (TypeError)
Fails:
def factorial(n)
puts n
n * factorial(n-1) unless n == 1
end
factorial(5)
As another example, this code works fine and is written in a similar way:
Works:
def count_down(number)
puts number
count_down(number - 1) unless number == 0
end
count_down(10)
this code works fine and is written in a similar way
No it isn’t. Your count_down isn’t similar at all, because it doesn’t return a value.
But your factorial does return a value, and each recursive call uses that value.
Well, your second example doesn’t say what to return when n is 1, so it returns nil and the call stack breaks down.
Your first example does say what to return when n is 1. That’s the difference.
I have a method to calculate the factorial of an input number
def fact( n )
if (n == 0)
1
else
n * fact(n-1)
end
end
I want to create a loop that will test what the maximum possible calculable value is for this method. For my machine this number is 8734, but I found that through trial and error.
My idea is to create a for/ each loop and test whether the returned result is a real number or not. I only want to puts the last numerical value that actually produces a real numerical result.
Thanks!
I would do something like this:
i = 1
loop do
begin
fact(i)
rescue SystemStackError
puts "stack level too deep at: #{i}"
break
end
i += 1
end
Note that this is a very naive algorith that checks every number and might take some time. It would be must faster to Do some kind of binary search on a range of numbers.
You can do as #spickermann suggests, but there is no need to search for the argument for fact at which the exception is raised. Rather, just compute fact(n) for any suitably large value of n (e.g. n = 100_000), increment a stack depth counter each time fact is called, and report the value of that counter when the SystemStackError exception is raised. The following code performs that calculation for various values of n, showing that the value of n is not important, so long as it is suitably large. I would think n = 100_000 would be plenty large for any Ruby implementation, but make it a million if you like.
def fact( n )
#stack_size += 1
if (n == 0)
1
else
n * fact(n-1)
end
end
[10_000, 20_000, 50_000, 100_000, 8733, 8732].each do |n|
print "n=#{n.to_s.ljust(6)}: "
begin
#stack_size = 0
fact(n)
rescue SystemStackError
puts "stack level too deep at: #{#stack_size}"
end
end
# n=10000 : stack level too deep at: 8733
# n=20000 : stack level too deep at: 8733
# n=50000 : stack level too deep at: 8733
# n=100000: stack level too deep at: 8733
# n=8733 : stack level too deep at: 8733
# n=8732 :
Note that the exception was not raised when n => 8732.
Does the maximum stack depth depend on the method? Most certainly! If we replace fact with:
def fact(n)
#stack_size += 1
fact(n-1)
end
we get:
# stack level too deep at: 9356
So I got this question as an assignment in Computer class and I literally have no idea why the solution was such. I am hoping someone can explain it thoroughly to me.
My problem is:
How does one know that n*(n-1)*(n-2)*...*2*1 is actually just the math expression n! Is this just a magical formula that I have to remember? (Yes, I don't know much math beyond arithmetic)
Is there a better way of programming factorials
Write a method that takes an integer n in; it should return
n*(n-1)*(n-2)*...*2*1. Assume n >= 0.
As a special case, factorial(0) == 1.
Difficulty: easy.
def factorial(n)
if n < 0
return nil
end
result = 1
while n > 0
result = result * n
n -= 1
end
return result
end
puts("factorial(0) == 1: #{factorial(0) == 1}")
puts("factorial(1) == 1: #{factorial(1) == 1}")
puts("factorial(2) == 2: #{factorial(2) == 2}")
puts("factorial(3) == 6: #{factorial(3) == 6}")
puts("factorial(4) == 24: #{factorial(4) == 24}")
Yes, that is the definition of a factorial. One knows it by having learned the definition.
There are many ways to code up a factorial. Yours happens to be the most basic one. As you learn more about Ruby, you will start to be able to write more idiomatic code. For example...
def factorial_functional(n)
n < 0 ? nil : (1..n).inject(1, &:*)
end
def factorial_recursive(n)
return if n < 0
return 1 if n == 0
n * factorial_recursive(n - 1)
end
It is arguable what is "better", since there are so many factors: readability, conciseness, speed, memory usage... And readability is directly related to the target audience: I'm sure your code is more readable to you than either of my examples, but to someone experienced it is much more of a hassle to go through your longer code.
Amadan already showed better ways of writing the factorials method, but I believe you were also asking for an explanation of the solution you brought in.
# The method `factorial` receives a number `n` and returns `n!`.
def factorial(n)
if n < 0 # If the number `n` is negative
return nil # `n!` can't be calculated, so return nothing.
end # Otherwise, go on...
result = 1 # `result` is 1. For now...
while n > 0 # While the number `n` is positive
result = result * n # `result` becomes `result` times `n`.
n -= 1 # Decrease the number `n` by one.
end
# Once the number `n` becomes zero, `result` is
# equal to the multiplication of all numbers from 1
# to what `n` was at the very beginning.
return result # Return `result`
end
I would also like to contribute the following "better" way of defining the factorial method that can be read, more or less, in plain English:
def factorial(number)
return unless number.is_a? Integer and number >= 0
total = 1
number.downto 1 do |this_number|
total = total * this_number
end
return total
end
This question references Project Euler Problem 5, so beware of spoilers!
Problem 5:
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder. What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
I wrote the following code in Ruby as a solution to Problem 5.
num = 2520
until (1..20).all?{|x| num % x == 0}
num += 1
end
puts "#{num}"
However, whenever I run the script, it just hangs. Note that I tested the same method on the base case 2520 for the range 1 to 10 and it worked just fine.
Why does it work for the simpler case but not for the more advanced case? What can I do to fix what I have?
It's slow because the answer is more than 200 million, and you're counting up to it in steps of 1. That's going to take a while. You need a better algorithm.
You won't be able to brute force this problem as you have with others. You're going to need to find a more efficient solution for it.
SPOILER BELOW
This is a significantly more efficient way to do it (apologies if this isn't very Ruby-like):
def find_multiple
lcm = 1
(2..20).each do |i|
lcm *= i / gcd(lcm, i)
end
lcm
end
def gcd(a, b)
while b > 0
a %= b
return b if a == 0
b %= a
end
a
end
puts find_multiple
If you're looking for a more Ruby-like way to solve it, you can use the following (as suggested by steenslag in the comments):
(1..20).inject(:lcm)
A little late to the game but here's my input. If you like your code - which is succinct and pretty clear - you can make a couple of small adjustments to make it run faster. This worked for me without timing out:
num = 20
until (11..20).all?{ |i| num % i == 0 }
num +=20
end
puts num
Essentially you just increment by 20s since you know it needs to be divisible by 20, and you can skip iterating through anything in the lower 1/2 of the set.
Simplest and clean solution in ruby language.
(1..20).inject(:lcm) # output will be 232792560
Try this.
Code:
i=2520
max_product = (4..19).inject(1){|j,k| j*k}
puts max_product
while i < max_product
if( [3, 7].inject(true) do |memo, p|
memo && i%p==0
end)
if(
(4..20).inject(true) do |memo, p|
memo && i%p==0
end
)
puts i
end
end
i+=10
end
I'm going crazy: Where is the Ruby function for factorial? No, I don't need tutorial implementations, I just want the function from the library. It's not in Math!
I'm starting to doubt, is it a standard library function?
There is no factorial function in the standard library.
Like this is better
(1..n).inject(:*) || 1
It's not in the standard library but you can extend the Integer class.
class Integer
def factorial_recursive
self <= 1 ? 1 : self * (self - 1).factorial
end
def factorial_iterative
f = 1; for i in 1..self; f *= i; end; f
end
alias :factorial :factorial_iterative
end
N.B. Iterative factorial is a better choice for obvious performance reasons.
Shamelessly cribbed from http://rosettacode.org/wiki/Factorial#Ruby, my personal favorite is
class Integer
def fact
(1..self).reduce(:*) || 1
end
end
>> 400.fact
=> 64034522846623895262347970319503005850702583026002959458684445942802397169186831436278478647463264676294350575035856810848298162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709549671345290477020322434911210797593280795101545372667251627877890009349763765710326350331533965349868386831339352024373788157786791506311858702618270169819740062983025308591298346162272304558339520759611505302236086810433297255194852674432232438669948422404232599805551610635942376961399231917134063858996537970147827206606320217379472010321356624613809077942304597360699567595836096158715129913822286578579549361617654480453222007825818400848436415591229454275384803558374518022675900061399560145595206127211192918105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
This implementation also happens to be the fastest among the variants listed in Rosetta Code.
update #1
Added || 1 to handle the zero case.
update #2
With thanks and appreciation to Mark Thomas, here's a version that is a bit more efficient, elegant and obscure:
class Integer
def fact
(2..self).reduce(1,:*)
end
end
In math, factorial of n is just the gamma function of n+1
(see: http://en.wikipedia.org/wiki/Gamma_function)
Ruby has Math.gamma() so just use Math.gamma(n+1) and cast it back to an integer if desired.
You could also use Math.gamma function which boils down to factorial for integer parameters.
class Integer
def !
(1..self).inject(:*)
end
end
examples
!3 # => 6
!4 # => 24
I would do
(1..n).inject(1, :*)
I just wrote my own:
def fact(n)
if n<= 1
1
else
n * fact( n - 1 )
end
end
Also, you can define a falling factorial:
def fall_fact(n,k)
if k <= 0
1
else
n*fall_fact(n - 1, k - 1)
end
end
With high respect to all who participated and spent their time to help us, I would like to share my benchmarks of the solutions listed here.
Params:
iterations = 1000
n = 6
user system total real
Math.gamma(n+1) 0.000383 0.000106 0.000489 ( 0.000487)
(1..n).inject(:*) || 1 0.003986 0.000000 0.003986 ( 0.003987)
(1..n).reduce(1, :*) 0.003926 0.000000 0.003926 ( 0.004023)
1.upto(n) {|x| factorial *= x } 0.003748 0.011734 0.015482 ( 0.022795)
For n = 10
user system total real
0.000378 0.000102 0.000480 ( 0.000477)
0.004469 0.000007 0.004476 ( 0.004491)
0.004532 0.000024 0.004556 ( 0.005119)
0.027720 0.011211 0.038931 ( 0.058309)
Just call this function
def factorial(n=0)
(1..n).inject(:*)
end
examples
factorial(3)
factorial(11)
Using Math.gamma.floor is an easy way to produce an approximation and then round it back down to the correct integer result. Should work for all Integers, include an input check if necessary.
Just another way to do it, although it really isn't necessary.
class Factorial
attr_reader :num
def initialize(num)
#num = num
end
def find_factorial
(1..num).inject(:*) || 1
end
end
number = Factorial.new(8).find_factorial
puts number
You will probably find a Ruby feature request useful. It contains a nontrivial patch that includes a demo Bash script. The speed difference between a naive loop and the solution presented in the batch can be literally 100x (hundred fold). Written all in pure Ruby.
Here is my version seems to be clear to me even though it's not as clean.
def factorial(num)
step = 0
(num - 1).times do (step += 1 ;num *= step) end
return num
end
This was my irb testing line that showed each step.
num = 8;step = 0;(num - 1).times do (step += 1 ;num *= step; puts num) end;num
Why would the standard library require a factorial method, when there is a built-in iterator for this exact purpose? It is called upto.
No you do not need to use recursion, like all these other answers show.
def fact(n)
n == 0 ? 1 : n * fact(n - 1)
end
Rather, the built-in iterator upto can be used to calculate factorials:
factorial = 1
1.upto(10) {|x| factorial *= x }
factorial
=> 3628800
class Integer
def factorial
return self < 0 ? false : self==0 ? 1 : self.downto(1).inject(:*)
#Not sure what other libraries say, but my understanding is that factorial of
#anything less than 0 does not exist.
end
end
And yet another way (=
def factorial(number)
number = number.to_i
number_range = (number).downto(1).to_a
factorial = number_range.inject(:*)
puts "The factorial of #{number} is #{factorial}"
end
factorial(#number)
Just one more way to do it:
# fact(n) => Computes the Factorial of "n" = n!
def fact(n) (1..n).inject(1) {|r,i| r*i }end
fact(6) => 720
In Ruby standard library function for factorial is not available. We can make a simple function of factorial in ruby in this way.
def factorial_number(n)
if n <= 1
1
else
n * factorial_number(n-1)
end
end
puts factorial_number(6) #Output is 720 => (6*5*4*3*2*1)
puts factorial_number(8) #Output is 40320 => (8*7*6*5*4*3*2*1)