3

I'm trying to define a procedure which takes a column c and a row r, counting from 0 and returns the number at that spot in the triangle:

def pascal(c: Int, r: Int): Int = {
    if (c <= 0) 1
    else
        println(pascal(r, c-1) * (r-c)/c)
        pascal(r, c-1) * (r-c)/c
}

When I run my code:

>>>pascal(1,3) 

I have the following error:

pascal: (c: Int, r: Int)Int
java.lang.StackOverflowError

How can I fix that?

Thanks.

Michael
  • 15,386
  • 36
  • 94
  • 143

6 Answers6

9

To get an element of the pascal triangle, you simply need to add the prev row's 2 elements.

The following code will do that correctly.

def pascal(c: Int, r: Int): Int = {
    if (c <= 0 || c == r) 1
    else pascal(c, r-1) + pascal(c-1, r-1)
}  
3

I don't think you should be calling pascal function again in your println, you should also use curly braces. I've rewritten it a little bit:

def pascal(c: Int, r: Int): Int = {
  var p = 1
  if (c > 0) {
    p = pascal(r, c-1) * (r-c)/c 
    println(p)
  }
  p
}

This prints for pascal(1,3):

-1
-2

UPDATE: I was curious to write a correct solution and this is what I ended up with:

  def fact(n: Int, r: Int=1): Int = if (n==0) r else fact(n-1, n*r)

  def pascal(c: Int, r: Int): Int = {
    fact(c) / (fact(r) * fact(c-r))
  }

  def main(a: Array[String]) { 
    println(pascal(3, 2))
  }

The only problem (that I know of) is the coordinates must be correct, with indices starting from 0. Anything out of bounds of the Pascal's triangle will cause a division by zero, this includes the OP's given example of pascal(1,3) - there's only two numbers on the row #1.

maksimov
  • 5,792
  • 1
  • 30
  • 38
  • And it's not even a pascal triangle :-) I'll rewrite. – maksimov Sep 24 '13 at 10:30
  • I don't know :-/ Guess it's fixed the StackOverflowError for the short term. Hopefully the OP can un-accept it. – maksimov Sep 24 '13 at 11:00
  • That's the one thing it can't do. In his original code, the two calls are sequential, not parallel. If the first completes without an overflow, so will the second. If the first overflows, the second would have done the same - so removing one call fixes nothing (but saves some time in non-overflow situations). – itsbruce Sep 24 '13 at 11:44
  • 1
    The `println` is irrelevant but "missing curly braces for the `else` statement" is the right answer. The function always evaluates to `pascal(r, c-1) * (r-c)/c` because that is the last expression, so it loops infinitely. Whereas OP expects it to evaluate to the if/else expression. – Luigi Plinge Sep 24 '13 at 12:44
  • Aye, adding the curly braces changes the stack overflow from a certainty to a possibility. – itsbruce Sep 24 '13 at 13:40
  • Apologies to maksimov :S – itsbruce Sep 24 '13 at 13:46
  • @itsbruce I'm actually thankful to you, because after your comments I went on to write the correct implementation, but I still can't get it to work even after moving the factorial into a separate function. – maksimov Sep 24 '13 at 14:02
  • Have a look here for some pointers: http://stackoverflow.com/questions/18945141/convert-normal-recursion-to-tail-recursion – itsbruce Sep 24 '13 at 18:56
3

You could try this version that calculates binomial coefficients that are the same as entries of Pascal's triangle:

  def pascal(col: Int, row: Int): Int = {

    val l = if (col > row / 2) col else row - col
    @tailrec
    def go(i: Int, acc: Int): Int = {
      if (i == l + 1) acc
      else go(i + 1, acc * (row - l + i) / i)
    }
    return go(1, 1);
  }

This solution uses tail recursion, so StackOverflowError is not a threat here.

rarry
  • 3,553
  • 20
  • 23
  • Very good point. I do not expect that pascal triangle has solution without remembers last row. – Andrzej Jozwik Sep 24 '13 at 14:19
  • @ajozwik You are wrong. It is possible to make an efficient, tail-recursive solution which builds only the necessary part of the triangle. See the fourth code example here: http://stackoverflow.com/questions/18945141/convert-normal-recursion-to-tail-recursion/18953869#18953869 – itsbruce Sep 24 '13 at 22:10
  • @itsbruce See above solution. You need to remember only i and acc. Two numbers (can be BigInt or other). So the solution do not need any extra memory. And it takes O(n) time. – Andrzej Jozwik Sep 25 '13 at 06:41
  • The solution I linked to also requires no extra memory. Tail-recursive, innit. It also solves the problem while only calculating the necessary part of the triangle, not each entire row, so it is faster than the above solution, for finding a single point. – itsbruce Sep 25 '13 at 08:19
2

Your Pascal's triangle algorithm is incorrect, but maybe you haven't finished it yet, so I'm not going to tell you how to write a correct algorithm, just how to stop the stack overflow.

EDIT: maksimov is right that by forgetting to wrap your else sequence in braces, you are only making the first expression conditional, which means that the second expression is always evaluated and loops infinitely into stack overflow. Adding the braces, however, will only change a 100% probability of stack overflow into a possibility of a stack overflow, because the calls to your pascal function are not in tail position. To remove the risk of stack overflow, you have to make further modifications, explained below...

Recursive functions can avoid stack overflows by using tail recursion. However, for that to work, the recursive call has to be in tail position. That is, the recursive call must be the final expression to be executed before the function returns and its value must be returned without modification, all the way back up the stack to the first invocation. Since your calculation uses pascal(r, c-1) * (r-c)/c, you are always modifying the returned value before returning that modified result, so the call is not in tail position. You need to modify your function so that when it finally returns it gives the correct result with no need for modification. The end result should have this basic shape...

def pascal(c: Int, r: Int): Int = {
  ...
  if (c <= 0) 1 else pascal(..., ...)
}

You will find that the only way to do this is to define a local function inside your pascal function and have that do the recursion....

def pascal(c: Int, r: Int): Int = {
  def loop(...): Int = ... match {
    case ... => 1
    case ... => x + y
    case ... => loop(...)
    case _ => loop(...)
  }
  ...
  if (c <= 0) 1 else loop(...)
}

This is because the recursive function will have to check state to find out whether it has solved the final problem or a sub-task within the problem. The state can be extra parameters passed to loop or local vars defined at the top level of pascal

Only once you have safely moved the recursion into the local function can you safely do what maksimov suggested

var p = if (c <= 0) 1 loop(...)
println(p)
p

You can do this safely because the recursive calls all happen inside loop and are all (if you use my template) in tail position.

To be clear: having two successive calls to your pascal function is not the cause of the overflow. The two top-level calls in your code are sequential and do not interfere with each other; if one completes, so will the other. If the first fails, the second one would also have failed (and removing the first one will not stop the second one from failing).

itsbruce
  • 4,825
  • 26
  • 35
  • Perhaps the downvoter could explain what is wrong or missing in this answer. – itsbruce Sep 24 '13 at 11:51
  • I didn't downvote but I think your answer is wrong because the problem isn't anything to do with tail calls. If it had a tail call it would just go into an infinite loop instead. – Luigi Plinge Sep 24 '13 at 12:47
  • You're right, Luigi - I missed that. With the curly brackets added, there is a *risk* of stack overflow, while without them there is *always* a stack overflow. – itsbruce Sep 24 '13 at 13:41
0

Here an example of the whole code:

object Main {

  def main(args: Array[String]) {
  println("Pascal's Triangle")

 for (row <- 0 to 10) {
  for (col <- 0 to row)
    print(pascal(col, row) + " ")

    println()
  }
 }


def pascal(c: Int, r: Int): Int = {
 if ( c <= 0 || c == r ){
    return 1
  }

  return pascal(c, r - 1) + pascal(c - 1, r -1)
}

}
Alex Guerreiro
  • 135
  • 2
  • 13
-1

Pure Functional Programming

def printPascalsTriangle(n: Int): Unit ={

    // n=1 print 1
    // n=2 print 1 1
    // n=3 print 1 2 1   List(prev(0),prev(0+1),prev(1))
    // n=4 print 1 3 3 1 List(prev.head,prev(0+1),prev(1+2),prev.reverse.head)

    def combine(oldList: List[Int], newList: List[Int]) = List(oldList.head) ::: newList ::: List(oldList.reverse.head)

    def g(prevList:List[Int],v:Int) = List(prevList(v-1), prevList(v))

    def pascalLine(prevList: List[Int], n: Int): List[Int] =
    {
      if(n>0)
      prevList match {
        case Nil => {println(List(1));pascalLine(List(1),n-1)}
        case List(1) => {println(List(1,1));pascalLine(List(1,1),n-1)}
        case _ => {
          val newList=combine(prevList,(1 to prevList.length-1).map(x => g(prevList,x)).map(y=>y.sum).toList)
          println(newList)
          pascalLine(newList,n-1)
        }

      }
      else
        Nil
    }
    pascalLine(Nil,n)
}
Community
  • 1
  • 1