Program fails with return code 128

Started by
15 comments, last by Antheus 14 years, 1 month ago
Quote:
Maybe, but the program never goes above 1% total memory usage according to top in linux. Anyway to increase stack space for a program?

stack space isn't going to show up as a huge memory usage. most the time you only have a few megs of stack space.
You can increase it with different compiler options, but you'd be better off rewriting the function to be non recursive. see my edit above.
Advertisement
Quote:Original post by Zael
Quote:Original post by KulSeran
Quote:
It seems to often die in the middle of the map;

Sorry i didn't see that before. You have a recursive function there.
If it is dieing in the middle of the map, you probably ran out of stack space due to recursing too deep.

Hmm... Maybe, but the program never goes above 1% total memory usage according to top in linux. Anyway to increase stack space for a program?

You could test the hypothesis using the ulimit command, namely the -s switch.

Quote:Or maybe a better question is: Is there a better way to do what I am trying to accomplish?

Rewrite the function in question.
Ok... Thanks guys. I will just try rewriting the function.
Wow, talk about recursion. That function has a complexity of O(2^(3n)).

One thing you could do to seriously reduce this is marking each cell as closed after you visit it. For example, if all you're trying to do is determine if something is part of a connected land mass or water mass, then why do you care about a cell if you've previously arrived there through some other path? In that case you should already know what it's connected to.

So at the beginning of the function, you just check "is this cell closed, if so return immediately".
Quote:Original post by cache_hit
Wow, talk about recursion. That function has a complexity of O(2^(3n)).

One thing you could do to seriously reduce this is marking each cell as closed after you visit it. For example, if all you're trying to do is determine if something is part of a connected land mass or water mass, then why do you care about a cell if you've previously arrived there through some other path? In that case you should already know what it's connected to.

So at the beginning of the function, you just check "is this cell closed, if so return immediately".


It already does that. I didn't explained that group is never equal to 1. 1 is the initialized value though for land masses. As soon as a cell is placed into a group it is no longer equal to one. While the program doesn't immediately return it doesn't go through the if statement... so unless there is some low level stuff going on here that I don't realize, it essentially does return immediately.
Let's clean up the code a bit first:

For a square (rectangular) array in general, boost::multi_array is a better idea than std::vector. Also, let's take out the debugging stuff for now (because it's told us as much as we can really figure out from it) - although for future reference, it's better to send debug output to std::cerr instead; that way you don't have to worry about flushing at all, and it actually exists for the purpose of reporting errors and stuff like that. Finally, let's not repeat ourselves; factor out the common sub-expressions for adjacent cell coordinates. (That provides some insurance against typos, too.) Finally, there is no point in having a return value from the function, and writing the initial check as a guard clause probably is cleaner (makes things less indented) even if it doesn't impact the actual algorithm.

void followLand(boost::multi_array<unsigned int, 2>& tmpmap, unsigned int x, unsigned int y, unsigned short group) {	if (tmpmap[x][y] != 1) return;	tmpmap[x][y] = group;	int size = tmpmap.shape()[0];	int next_x = (x + 1) % size;	int prev_x = (x + size - 1) % size;	int next_y = (y + 1) % size;	int prev_y = (y + size - 1) % size;	followLand(tmpmap, prev_x, prev_y, group);	followLand(tmpmap, prev_x, y, group);	followLand(tmpmap, prev_x, next_y, group);	followLand(tmpmap, x, prev_y, group);	followLand(tmpmap, x, next_y, group);	followLand(tmpmap, next_x, prev_y, group);	followLand(tmpmap, next_x, y, group);	followLand(tmpmap, next_x, next_y, group);}


Then the next step is to convert to iteration with a stack. To do this we'll want to make a temporary structure to represent the data that changes with each currently recursive call, i.e. the coordinate.

void followLand(boost::multi_array<unsigned int, 2>& tmpmap, unsigned int x, unsigned int y, unsigned short group) {	int size = tmpmap.shape()[0];	std::vector<std::pair<int, int> > coordinates;	coordinates.push_back(std::make_pair(x, y));	while (!coordinates.empty()) {		std::pair<int, int> coordinate = coordinates.pop_back();		x = coordinate.first;		y = coordinate.second;		if (tmpmap[x][y] != 1) { continue; }		tmpmap[x][y] = group;		int next_x = (x + 1) % size;		int prev_x = (x + size - 1) % size;		int next_y = (y + 1) % size;		int prev_y = (y + size - 1) % size;		// These will be processed in the reverse order compared to the		// original code, but because we use the vector as a stack,		// we'll still process "depth-first". To process 		// "breadth-first", use queue logic instead. For a queue you		// probably don't want to use std::vector, though. Consider		// std::deque instead.		coordinates.push_back(std::make_pair(prev_x, prev_y));		coordinates.push_back(std::make_pair(prev_x, y));		coordinates.push_back(std::make_pair(prev_x, next_y));		coordinates.push_back(std::make_pair(x, prev_y));		coordinates.push_back(std::make_pair(x, next_y));		coordinates.push_back(std::make_pair(next_x, prev_y));		coordinates.push_back(std::make_pair(next_x, y));		coordinates.push_back(std::make_pair(next_x, next_y));	}}


BTW, why do you pass 'unsigned short group' if your group IDs are allowed to be 'unsigned int' within the actual storage?
Flood fill algorithm.

This topic is closed to new replies.

Advertisement