Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

prime number function 1

Status
Not open for further replies.

dingleberry

Programmer
Dec 13, 2002
143
US
I was bored about a week ago and that got me to thinking. I did not know of a function to calculate prime numbers (and there might be one but I couldn't find it.) I decided to write one. Basically it starts with a range of numbers (10000) and starts at 1. It takes every number up to that number and runs a fmod function on it to determine if there is any remainder. You can imagine however that this function is wildly resourse intensive as the number increases because if for instance the number is 1111, the computer needs to calculate 1111/1 (match) and 1111/2 (no match) and 1111/3 (no match) etc until it get's more than 2 matches and then the loop exits and the number goes to 1112 and it starts all over again. To make this function lean as possible I've added a few immediate checks to kill the loop if true such as if the number is even we know it's not a prime and if the sum of the numbers of the number equals nine we know it's divisible by nine so that kills the loop (for instance 2322 -- 2+3+2+2=9 so 2322/9 is 258.) Also because we know the numerator is odd due to the fact that the function immediately throws out even numbers so that if the demoninator is even, we increase the denominator by 1 to make it odd because an odd divided by an even will always have a remainder.

I'm looking for some more tests to run to kill this loop if true or false. Any suggestions appreciated.

Another issue is my install of php does not include the str_split function and I don't know why so I had to write one at the bottom of the program and call that. Anyone know why str_split is not a valid function in my situation? Is that part of a library or something I did not compile with?

I've attached the program below. Use it if you want and modify it as you see fit but let me know what you do to make this more efficient. Currently I can only run about 5450 numbers before the 30 second timeout occurs. My goal would be to get it to 10000 or higher.

<?


$number = 10000;
$x = 1;
$count=0;
$y=1;
$g=2;


while ($x <= $number)
{
$even=fmod($x, $g);
if ($even==0)
{
# this means that we have an even numerator so count goes to three to disrupt following while loop.
$count=3;
}
else if (array_sum(str_split($x))==9)
{
$count=3;
# this means that the sum of the integers of the number is nine which means it's divisable by nine.
}

while (($count<=2) && ($y<=$x))
{
$yeven = fmod($y, $g);
if ($yeven==0)
{
# this means that the denominator is even in the equation and because we know that our numerator is odd due to the last loop, we can exclude it.
# echo "for $x we bombed here because y is $y<br>";
$y++;
}
$z=fmod($x, $y);
if ($z==0)
{
$y++;
$count++;
}
else if ($z<>0)
{
$y++;
}
}
if ($count <= 2)
{
echo "$x is a prime<br>";
}
$count=0;
$y=1;
$x++;
}


function str_split($split_length)
{
preg_match_all('/.{1,' . $split_length . '}/s', $string, $matches);

return $matches[0];
}

?>


Thanks,
Dan
 
I did it !!!

Here is the final "primes" function, it's incredibly fast.

If you created the primes_inc.php as I showed previously just replace this function. Usage of the function is the same.

------
function primes( $n, $debug )
{
global $prime_number;

$result = "";
$root = floor( sqrt( $n ) );
$nbr_primes = count( $prime_number );
$last_prime = $prime_number[$nbr_primes - 1];

if( $root > $last_prime )
extend_primes( $root, $debug );

if( is_prime( $n, $debug ) )
{
$result = $n;
}
else
{
$found = 0;
for( $i = 1; ($i < $nbr_primes) && ($root >= $prime_number[$i]) && !$found; $i++ )
{
$found = ( ($n % $prime_number[$i]) == 0 );
}
$i--;
if( $found )
$result = $prime_number[$i]."|".primes( ($n / $prime_number[$i]), $debug );
else
$result = "#";
}
return( $result );
}
------

Have a good work.
 
The difference between our algorithms can only be seen on very large numbers. I modified my example to be similar to yours.

Try on your page 23400000 to 23410000 (that is 10,000 !!!) and then try them on mine :


On yours the 30 secs exception occures after 23405749 (about half of the job).

On mine it still runs (about 3.3 secs !!!) and you can even still ask to insert prime factors of all the non prime numbers of the range within the fatidic 30 secs (about 26 secs).

I'm pretty sure it would be very difficult to be much more efficient than this algorithm. Perhaps with very sophisticated mathematics ?

If you still want to improve your algorithm anyway, I suggest that you don't rely so much on float mathematics which are CPU consuming. As an example why do you use float function "fmod" in place of "%" operator which is faster as it works on integers ?

Hope this can still help. (=;
 
If you want to benchmark the comparisons you're going to need both scripts on one server... comparing across boxes is a complete waste of time and effort.

 
And technically by wich number other than 1 can 1 be divided to give an integer ?

For the benchmark it's right they should be compared on the same server.

If you want to do so on your own server just follow these instructions for my program :

(1) Create the "prime_numbers.php" file and import this :

<?PHP
$debug = 0;
$get_primes = 0;

include( "Includes/getParams_inc.php" );
include( "Includes/primes_inc.php" );

function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}

$the_version = explode( ".", phpversion() );
$version = $the_version[0];

if( $debug == "" )
$debug = 0;

if( $first == "" )
$first = 0;

if( $last == "" )
$last = 10;

$work_debug = $debug;
if( ($last - $first) > 10 )
$work_debug = 0;
?>
<html>
<body>
<hr>
<form action="prime_numbers.php" method="post">
<center>
PHP version is <b><?PHP echo( phpversion() ); ?></b><br><br>
First&nbsp;:&nbsp;<input type="text" name="first" value="<?PHP echo( $first ) ?>" length="6">
&nbsp;
Last&nbsp;:&nbsp;<input type="text" name="last" value="<?PHP echo( $last ) ?>" length="6"><br>
<input type="checkbox" name="get_primes" value="1"<?PHP if( $get_primes ) echo( " checked" ) ?>>
&nbsp;get primes of other ones
&nbsp;|&nbsp;
<input type="checkbox" name="debug" value="1"<?PHP if( $debug ) echo( " checked" ) ?>>
&nbsp;debug (will only work if (last - first) <= 10)<br>
<input type="submit" name="submit" value="Test">
</center>
</form>
<hr>
<?PHP
if( version == 5 )
$time_start = microtime();
else
$time_start = microtime_float();
for( $i = $first; $i <= $last; $i++ )
{
if( is_prime( $i, $work_debug ) )
{
echo( "<b>".$i."</b> is a prime.<br>" );
}
else
{
if( $get_primes )
echo( $i." = ".str_replace( "|", " * ", primes( $i, $work_debug ) ) .".<br>");
}
}
if( version == 5 )
$time_end = microtime();
else
$time_end = microtime_float();
echo( "<br>Execution time was <b>".($time_end - $time_start)."</b> seconds.<br>" );
?>
<hr>
</body>
</html>


Create a sub-folder "Includes" (take care to the upper "I")

In this new folder create "getParams_inc.php" importing

<?PHP
if( !strcasecmp( strtoupper( $_SERVER["REQUEST_METHOD"] ), "GET" ) )
{
foreach( $HTTP_GET_VARS as $name => $value )
{
$$name = $value;
}
}

if( !strcasecmp( strtoupper( $_SERVER["REQUEST_METHOD"] ), "POST" ) )
{
foreach( $HTTP_POST_VARS as $name => $value )
{
$$name = stripslashes($value);
}

foreach( $_FILES as $name => $value )
{
$$name = $value;
}
}
?>

and, last but not least, in the same "Includes" folder create "primes_inc.php" importing

<?PHP
global $prime_number;

array( $prime_number );

$prime_number[] = 1;
$prime_number[] = 2;
$prime_number[] = 3;
$prime_number[] = 5;
$prime_number[] = 7;
$prime_number[] = 11;
$prime_number[] = 13;
$prime_number[] = 17;
$prime_number[] = 19;
$prime_number[] = 23;
$prime_number[] = 29;
$prime_number[] = 31;
$prime_number[] = 37;
$prime_number[] = 41;
$prime_number[] = 43;
$prime_number[] = 47;
$prime_number[] = 53;
$prime_number[] = 59;
$prime_number[] = 61;
$prime_number[] = 67;
$prime_number[] = 71;
$prime_number[] = 73;
$prime_number[] = 79;
$prime_number[] = 83;
$prime_number[] = 89;
$prime_number[] = 97;

function extend_primes( $n, $debug )
{
global $prime_number;

$nbr_primes = count( $prime_number );
$last_prime = $prime_number[$nbr_primes - 1];

for( $i = $last_prime + 2; $last_prime < $n; $i += 2 )
{
if( is_prime( $i, $debug ) )
{
$prime_number[] = $i;
$last_prime = $i;
if( $debug )
echo( "extend_primes - prime_number array extended to ".$i.".<br>" );
}
}
return( $result );
}

function is_prime( $n, $debug )
{
global $prime_number;

$is_not_prime = 0;

$root = floor( sqrt( $n ) );
$nbr_primes = count( $prime_number );
$last_prime = $prime_number[$nbr_primes - 1];
if( $debug )
echo( "is_prime - Number of numbers in prime_number array is ".$nbr_primes." and the last one is ".$last_prime.".<br>" );

if( $root <= $last_prime )
{
if( $debug )
echo( "is_prime - Square root of ".$n." (".$root.") is lower than ".$last_prime." just check with numbers in prime_number array up to ".$root.".<br>" );

if( $debug )
echo( "is_prime -" );
for( $i = 1; ($i < $nbr_primes) && ($root >= $prime_number[$i]) && !$is_not_prime; $i++ )
{
if( $debug )
echo( " ".$i.":".$prime_number[$i] );
$is_not_prime = ( ($n % $prime_number[$i]) == 0 );
}
if( $debug )
echo( "<br>" );

return( !$is_not_prime );
}
else
{
if( $debug )
echo( "is_prime - ".$root." is greater than ".$last_prime." extend primes.<br>" );

extend_primes( $root, $debug );
return( is_prime( $n, $debug ) );
}
}

function primes( $n, $debug )
{
global $prime_number;

$result = "";
$root = floor( sqrt( $n ) );
$nbr_primes = count( $prime_number );
$last_prime = $prime_number[$nbr_primes - 1];

if( $root > $last_prime )
extend_primes( $root, $debug );

if( is_prime( $n, $debug ) )
{
if( $debug )
echo( "primes - ".$n." is a prime number, just return it as result.<br>" );
$result = $n;
}
else
{
if( $debug )
echo( "primes - ".$n." is not a prime number, find lower divisor in prime_number array and call recursively.<br>" );
$found = 0;
if( $debug )
echo( "primes -" );
for( $i = 1; ($i < $nbr_primes) && ($root >= $prime_number[$i]) && !$found; $i++ )
{
if( $debug )
echo( " ".$i.":".$prime_number[$i] );
$found = ( ($n % $prime_number[$i]) == 0 );
}
if( $debug )
echo( "<br>" );
$i--;
if( $found )
{
if( $debug )
echo( "primes - Divisor found in prime_number array for ".$n." is ".$prime_number[$i].".<br>" );
$result = $prime_number[$i]."|".primes( ($n / $prime_number[$i]), $debug );
}
else
{
if( $debug )
echo( "primes - Should never occure, big panic.<br>" );
$result = "#";
}
}
return( $result );
}
?>

And you get it !!!

But do you really think that my provider's server (it is not my main provider and I even don't know what kind of machine it is) could be about 20 time faster than the one of dingleberry's provider.

Anyway I'm interested by the comparison.

Enjoy.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top