8

I have a function that is recursively calling itself, and i want to detect and terminate if goes into an infinite loop, i.e - getting called for the same problem again. What is the easiest way to do that?

EDIT: This is the function, and it will get called recursively with different values of x and y. i want to terminate if in a recursive call, the value of the pair (x,y) is repeated.

int fromPos(int [] arr, int x, int y) 
0

11 Answers 11

21

One way is to pass a depth variable from one call to the next, incrementing it each time your function calls itself. Check that depth doesn't grow larger than some particular threshold. Example:

int fromPos(int [] arr, int x, int y) { return fromPos(arr, x, y, 0); } int fromPos(int [] arr, int x, int y, int depth) { assert(depth < 10000); // Do stuff if (condition) return fromPos(arr, x+1, y+1, depth + 1); else return 0; } 
Sign up to request clarification or add additional context in comments.

3 Comments

I would prefer if the method signature stays the same.
Just use overloading to provide a backward compatable signature.
In that case, you secretly call a 2nd function with the depth argument. See revised answer.
11

If the function is purely functional, i.e. it has no state or side effects, then you could keep a Set of the arguments (edit: seeing your edit, you would keep a Set of pairs of (x,y) ) that it has been called with, and every time just check if the current argument is in the set. That way, you can detect a cycle if you run into it pretty quickly. But if the argument space is big and it takes a long time to get to a repeat, you may run out of your memory before you detect a cycle. In general, of course, you can't do it because this is the halting problem.

4 Comments

yeah, just realized its the halting problem. Maybe i should put a bounty on it. :D
This method does not detect if it is legal to for the function to sometimes call itself with the same values -- whereas the recursion depth method can work for the general case.
Oh, and it requires the overhead of constructing the set and the entries therein.
@BillyONeal: I said "if the function has no state or side effects" (I should also add "and does not depend on any external state"); in that case, it is not okay for a function to call itself with the same values
4

You will need to find a work-around, because as you've asked it, there is no general solution. See the Halting problem for more info.

Comments

2

An easy way would be to implement one of the following:

Pass the previous value and the new value to the recursive call and make your first step a check to see if they're the same - this is possibly your recursive case.

Pass a variable to indicate the number of times the function has been called, and arbitrarily limit the number of times it can be called.

Comments

2

You can only detect the most trivial ones using program analysis. The best you can do is to add guards in your particular circumstance and pass a depth level context. It is nearly impossible to detect the general case and differentiate legitimate use of recursive algorithms.

Comments

1

You can either use overloading for a consistent signature (this is the better method), or you can use a static variable:

int someFunc(int foo) { static recursionDepth = 0; recursionDepth++; if (recursionDepth > 10000) { recurisonDepth = 0; return -1; } if (foo < 1000) someFunc(foo + 3); recursionDepth = 0; return foo; } 

John Kugelman's answer with overloading is better beacuse it's thread safe, while static variables are not.

Billy3

Comments

0

Looks like you might be working on a 2D array. If you've got an extra bit to spare in the values of the array, you can use it as a flag. Check it, and terminate the recursion if the flag has been set. Then set it before continuing on.

If you don't have a bit to spare in the values, you can always make it an array of objects instead.

Comments

0

If you want to keep your method signature, you could keep a couple of sets to record old values of x and y.

static Set<Integer> xs; static Set<Integer> ys;//Initialize this! static int n=0;//keeps the count function calls. int fromPos(int [] arr, int x, int y){ int newX= getX(x); int newY= getY(y); n++; if ((!xs.add(Integer.valueOf(newX)) && !ys.add(Integer.valueOf(newY))){ assert(n<threshold); //threshold defined elsewhere. fromPos(arr,newx,newy); } } 

1 Comment

What about the case when its not getting repeated in the immediate next call but after some intervening calls?
0

IMHO Only loops can go into an infinite loop.

If your method has too many level of recursion the JVM will throw a StackOverflowError. You can trap this error with a try/catch block and do whatever you plan to do when this condition occurs.

Comments

0

A recursive function terminates in case a condition is fulfilled.

Examples:

  • The result of a function is 0 or is 1
  • The maximum number of calls is reached
  • The result is lower/greater than the input value

In your case the condition is ([x0,y0] == [xN,yN]) OR ([x1,y1] == [xN,yN]) OR ([xN-1,yN-1] == [xN,yN])

0, 1, ...N are the indexes of the pairs

Thus you need a container(vector, list, map) to store all previous pairs and compare them to the current pair.

Comments

0

First use mvn findbugs:gui to open a gui which point to the line where this error is present.

I also faced the same problem and I solved it by adding a boolean variable in the loop verification.

Code before ->

for (local = 0; local < heightOfDiv; local = local + 200) { // Line under Error tileInfo = appender.append(tileInfo).append(local).toString(); while (true) { try { tileInfo = appender.append(tileInfo).append(getTheTextOfTheElement(getTheXpathOfTile(incr))).toString(); incr++; } catch (Exception e) { incr = 1; tileInfo = appender.append(tileInfo).append("/n").toString(); } } 

To Solve this problem, I just added a boolean variable and set it to false in the catch block. Check it down

for (local = 0; local < heightOfDiv; local = local + 200) { tileInfo = appender.append(tileInfo).append(local).toString(); boolean terminationStatus = true; while (terminationStatus) { try { tileInfo = appender.append(tileInfo).append(getTheTextOfTheElement(getTheXpathOfTile(incr))).toString(); incr++; } catch (Exception e) { incr = 1; tileInfo = appender.append(tileInfo).append("/n").toString(); terminationStatus = false; } } 

This is how i Solved this problem. Hope this will help. :)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.