Search code examples
rrecursionstack-overflow

Can I fix this recursive function so that the calls aren't deep?


I am taking a class on R, and I've been asked to implement Newton's square root method. I've done this before, but in functional languages using tail recursion where the stack doesn't fill because the math is done with each recursive call and not on callbacks.

I have implemented the function. But am getting: 'Error: C stack usage 15924912 is too close to the limit' when I apply the function to very large numbers. I was wondering if my function could be revised to fix this issue.

my_sqr <- function(number, sqrt_guess = 1) {
  if (abs((number/sqrt_guess) - sqrt_guess) < .001) sqrt_guess
  else my_sqr(number, improve_guess(number,sqrt_guess))
}

improve_guess <- function(number, guess) {
  return ((guess + (number/guess)) / 2)
}

# test your script on few examples here, example
# Note I will use the results in check1, check2, check3 to grade your sqrt function
# my_test1 <- my_sqr(16)
# my_test2 <- my_sqr(25)
# my_test3 <- my_sqr(400)
# my_test4 <-my_sqr(5000000000000000)
check1 <- my_sqr(2)
check2 <- my_sqr(1e-60)
check3 <- my_sqr(1e+60)

The function works on every test except the last call "my_sqr(1e+60)". This is where I get the error.


Solution

  • That error prevets you from get into an never-end loop. You can use this function instead but, using 1e+56 or higher may be never ends...

    #here you can see those limits
    Cstack_info()
    
    #here is the code
    
    library(rbenchmark)  
    
    new_my_sqr <- function(number, sqrt_guess = 1) {
        while (abs((number/sqrt_guess) - sqrt_guess) > .001) {
            sqrt_guess <- ((sqrt_guess + (number/sqrt_guess)) / 2)
        }
        return (sqrt_guess)
    }
    
    #You can compare execution time with something like this...
    
    benchmark("See the change in time from 1e+55..." = {check3x1 <- new_my_sqr(1e+55)},
              "...to 1e+56" = {check3x2 <- new_my_sqr(1e+56)},
              replications = 2,
              columns = c("test", "replications", "elapsed")
    )