String is better than array: Memory exhausting calculation special case--Return all prime number below x

When I was working with the Sieve of Eratosthenes, a Sieve for finding all prime number below x, the input number. I have to keep track of an array that contains either 0 or 1. The size of the array equals to the input number.
The code before using string:

function esprime($limit){
	$sqrtlimit = sqrt($limit);
	$range = 1;
	while($range<$limit){
		$i[$range] = 1;
		$range+=2;
	}
	$n = 2;
	while($n < $sqrtlimit){
		if ($i[$n]){
			$sqn = $n*$n;
			$k = $sqn;
			$i[$k]=0;
			while($k<=$limit){
				$k += $n;
				$i[$k]=0;
			}
		}
		++$n;
	}
	$n = 1;
	while($n<$limit){
		if($i[$n]) $primes[] = $n;
		$n+=2;
	}
	if($limit>=2) $primes[0] = 2;
	return $primes;
}

This is extremely memory exhausting. 32MB of memory is all used up while trying to find all prime numbers up to 500,000.
32MB = 33,554,432 bytes
Without running the function, the script uses 4,786,192 bytes of memory. So 27 MB is used for creating a size 250,000 array(all the even ones are dropped).
Is there any way to fix this problem? This array have to be created instantly so you can't just drop values out from it. Doesn't that mean it's impossible for this to work?
There is really nothing we can do with array in this case.
Don't despair! we can use string!
Because the value of the array can be represent by a character, the key of the array can be represent by the position of the character in the string.
so instead of this code

$range = 1;
while($range<$limit){
	$i[$range] = 1;
	$range+=2;
}

I uses this:

$range = 0;
while($range<$limit){
	$i .= '11';
	$range+=2;
}

The good thing about this is I don't need to change my entire script, because each character inside a string can be accessed like an array by it's position:

$i = '30000'
echo $i[0];//3

Using the string method, I successfully made it run up to 5,000,000 with out a problem.
I don't know things like this will ever occur to a PHP programmer, because this is useful only when you are having limited memory but also having an array with huge amount of data that can be represent by a limited amount of keys.

Robert Mark Howting made it even better :)

$range = 0;
$i = str_repeat('01',floor($limit/2));

It's much more efficient. Except this time we have to have a case to output the even prime 2.
You can see it in the end of this script.

BTW, I'm also working on Sieve of Atkin. Strange I can't make it faster than Sieve of Eratosthenes.


Good example

Anders Törnkvist's picture

Nice :) Good example!

Have a nice day,
Anders Törnkvist

Post new comment

The content of this field is kept private and will not be shown publicly.
If you have a Gravatar account, used to display your avatar.
  • Allowed HTML tags: <img> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <span> <fn>
  • Lines and paragraphs break automatically.
  • Textual smileys will be replaced with graphical ones.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".
  • Use [fn]...[/fn] (or <fn>...</fn>) to insert automatically numbered footnotes.

More information about formatting options

What is 32 + 6?
To combat spam, please solve the math question above.
Honey Pot that kill bots