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
Related
I'm trying to implement merge sort on my own using recursion.
def merge_sort(a,i,j)
if i < j
merge_sort(a,i,j/2)
merge_sort(a,j/2+1,j)
merge(a,i,j/2,j/2+1,j)
end
end
def merge(a,i,j,k,l)
# No implementation yet
end
The problem is my implementation results in the stack going too deep. I shouldn't be getting this error message for such a small array. The array I'm trying to sort is just five elements.
b = [5,4,3,2,1]
p merge_sort(b,0,b.size - 1) # => results in 'stack to deep' message
Here's a step in the right direction that's made a bit more Ruby-like in how it's more forgiving, plus as a bonus has actual names instead of mathematical shorthand:
def merge_sort(arr,from = nil,to = nil)
from ||= 0
to ||= arr.length
if (from < to)
part = from + (to - from) / 2
merge_sort(arr, from, part)
merge_sort(arr, part + 1, to)
merge(arr, from,part, part+1, to)
end
end
def merge(a,from,j,k,l)
# No implementation yet
end
b = [5,4,3,2,1]
merge_sort(b)
The mistake came about from not properly defining the partition point. In the original code for an array of length 5 the cut point would be 2, and when that's further divided, the cut point is 2/1 or 1, not 2+(5-3)/2 or 3 as it should be. From there it all went crazy because it was doing the math wrong and kept calling itself for no reason.
My problem was my mid-point formula was off throwing the recursion into an infinite loop recursing until the stack overflowed. Instead of
j / 2 + 1
It should have been
(i+j) / 2 + 1
tadman got the formula right in his re-versioning
I am trying to find the highest prime number for a given integer. I can get the first portion of the code to work, but the part where I check to see if the factors are prime doesn't work. I don't get any errors, but the output (puts) I receive is blank, so I'm thinking a nil is being outputted. What's wrong with my code?
def highestprime num
i = 1
counter = 0
count = -1
factors = []
primes = []
while (i < num/2) #checks for all factors of number
i += 1
if (num%i == 0)
factors.push(i) #adds all factors to the end factors array
end
end
while (counter < factors.length) #goes through whole array
counter += 1
count += 1
while (i < factors[count]) #tests for particular index in array
i += 1
if (factors[count]%i == 0 and i != factors[count]) #if factor is divisible by a number, it is not prime, so break
break
elsif (factors[count]%i != 0 and i != factors[count]) #if it is not divisibe, then keep iterating
next
elsif (i == factors[count]) #if the end has been reached, then add to primes array
primes.push i
end
end
end
puts primes.pop #print the biggest(last) prime number
end
The first loop pushes some of the values of i into factors; when that loop is done, i is at least as big as every value in factors. The nested while loop, which is the only place anything can get pushed onto primes, only runs as long as i is less than some value in factors, which we just established never happens.
I see you are reusing the iterator variable i between loops, but I do not see where you reset it back to 1.
Maybe that?
You should check out the prime library. You can rewrite the entire thing in a few lines:
require 'prime'
def highestprime num
Prime.reverse_each(num) { |p| return p }
end
puts highestprime(10)
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
I have this ruby code:
def get_sum n
return 0 if n<1
(n%3==0 || n%5==0) ? n+get_sum(n-1) : get_sum(n-1) #continue execution
end
puts get_sum 999
Seems to be working for values up until 999. When I try 9999 it gives me this:
stack level too deep (SystemStackError)
So, I added this:
RubyVM::InstructionSequence.compile_option = {
:tailcall_optimization => true,
:trace_instruction => false
}
but nothing happened.
My ruby version is:
ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-darwin12.2.1]
I also increased the machine's stack size ulimit -s 32768 which I think is 32MB?
I don't think it is my code's fault as it works with smaller numbers, and I don't think 9999 is a big number. I have 8GB of RAM and I think it is more than enough. Any ideas/help?
Your method cannot take advantage of tail-call optimization (TCO) because it's not tail-recursive, the last expression of the method should be a call to the method itself, get_sum. So there is nothing wrong, simply you reached the recursion limit. With Ruby 1.9.3, that limit is:
def recursive(x)
puts(x)
recursive(x+1)
end
recursive(0)
...
8731
This method, on the other hand, is tail-recursive:
def self.get_sum_tc(n, acc = 0)
if n < 1
acc
else
get_sum_tc(n - 1, acc + ((n % 3 == 0 || n % 5 == 0) ? n : 0))
end
end
Your Ruby may or may not support it. In Ruby you can use recursion when you have some certainties about the depth-level you'll reach, but it's definitely not idiomatic to loop over a collection of unknown size. You usually have other abstractions for this kind of tasks, for example:
(1..9999).select { |x| x % 5 == 0 || x % 3 == 0 }.reduce(0, :+)
The problem is, you have a routine n+get_sum(n-1), when n has common factors 3 or 5, Ruby goes ahead to this routine. This cannot be optimized by tail-recursion. Ruby has to keep the current frame to remember the current n and only when get_sum(n-1) is computed can Ruby return and throw away the frame.
Generally, the stack space is expensive. By default, the operating system reserves fixed amount of stack space (say 1M, or maybe less) for each thread. This can be consumed up quickly. For your code, (9999/3 + 9999/5) recursive calls consumed all the stack space.
If you want to keep the recursive programming pattern, you have to change the behavior of your method call from recursive (your current state) to iterative.
def get_sum(n, sum = 0)
return sum if n < 1
if n % 3 == 0 || n % 5 == 0
get_sum(n - 1, sum + n)
else
get_sum(n - 1, sum)
end
end
However, it seems that Ruby's tail recursion optimization isn't that powerful. For the above code sample, there are two different get_sum() tail calls. Ruby won't optimize this. You'll have to rewrite the two calls into one.
And besides, to make this work with the RubyVM tweak you have provided, you have to load the method definition at runtime. That's because the RubyVM tweak happens at runtime. You can't put the method definition directly in the same file, or the method will be parsed at compile time and no optimization will take effect.
You can either put the get_sum in a separate file and require that lib after the RubyVM tweak:
# file: test_lib.rb
def get_sum(n, sum = 0)
if n < 1
sum
else
get_sum(n - 1, sum + (n % 3 == 0 || n % 5 == 0 ? n : 0))
end
end
# eof
# file: test.rb
RubyVM::InstructionSequence.compile_option = {
:tailcall_optimization => true,
:trace_instruction => false
}
require_relative 'test_lib'
puts get_sum(999999)
Or, use eval to evaluate the method definition in a String at runtime:
RubyVM::InstructionSequence.compile_option = {
:tailcall_optimization => true,
:trace_instruction => false
}
eval <<END
def get_sum(n, sum = 0)
if n < 1
sum
else
get_sum(n - 1, sum + (n % 3 == 0 || n % 5 == 0 ? n : 0))
end
end
END
puts get_sum(990000)
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.