1, only the least significant digit is
//considered.
function miller_rabin_isdigit($Digit)
{
$Digit = (string)$Digit;
//If the string has zero length, this is an error condition and return 0.
$Length = strlen($Digit);
if ($Length==0)
{
return(0);
}
//Obtain the trailing character of the string.
$Trailing_char = Substr($Digit, $Length-1, 1);
//Do a switch and return an integer based on the character.
switch($Trailing_char)
{
case "9":
return 1;
break;
case "8":
return 1;
break;
case "7":
return 1;
break;
case "6":
return 1;
break;
case "5":
return 1;
break;
case "4":
return 1;
break;
case "3":
return 1;
break;
case "2":
return 1;
break;
case "1":
return 1;
break;
case "0":
return 1;
break;
default:
return 0;
break;
}
}
//
//
//Returns TRUE if the passed argument is a simple integer (no error
//codes, no commas), or FALSE otherwise.
function miller_rabin_issimpleint($Intnum)
{
$Intnum = (string)$Intnum;
//If the string has zero length, this is an error condition and return 0.
$Length = strlen($Intnum);
if ($Length==0)
{
return(0);
}
//If the first digit is "0", this must be the only character in the string,
//otherwise there is a leading-zero violation.
if (Substr($Intnum, 0, 1)=="0")
{
if ($Length==1)
{
return 1;
}
else
{
return 0;
}
}
//If the first character is a "-" sign, it may not be the only character,
//and it may not precede a "0" (which would again be a leading 0 violation).
//If it is a "-", we can exclude "0" and parse as a positive.
if (Substr($Intnum, 0, 1)=="-")
{
if ($Length==1)
{
return 0;
}
else
{
if (Substr($Intnum, 1, 1) == "0")
{
//This is illegal (a "-" followed by a "0").
return 0;
}
else
{
//We can just remove the "-" and parse as a positive.
$Intnum = Substr($Intnum, 1, $Length - 1);
$Length--;
}
}
}
//It is known at this point that the length is at least 1 and the leading
//character is not zero. All we need to do at this point is check that each
//and every character is a digit.
for ($index=0; $index < $Length; $index++)
{
if (!miller_rabin_isdigit(Substr($Intnum, $index, 1)))
return 0;
}
return 1;
}
//
//
//Returns the number of digits in the argument, which must be a valid simple
//integer.
function miller_rabin_ndigits($Intnum)
{
$Intnum = (string)$Intnum;
if (Substr($Intnum, 0, 1) == "-")
{
$rv = strlen($Intnum) - 1;
}
else
{
$rv = strlen($Intnum);
}
return($rv);
}
//
//
//Given a string, converts the final character to an integer. If the character
//is not a digit, returns 0.
function miller_rabin_digittoint($Digit)
{
//echo "Digit is: ";
//echo $Digit;
//echo "
";
$Digit = (string)$Digit;
//echo "Digit is: ";
//echo $Digit;
//echo "
";
//If the string has zero length, this is an error condition and return 0.
$Length = strlen($Digit);
//echo "Length is: ";
//echo $Length;
//echo "
";
if ($Length==0)
{
return(0);
}
//Obtain the trailing character of the string.
$Trailing_char = Substr($Digit, $Length-1, 1);
//echo "Trailing char is: ";
//echo $Trailing_char;
//echo "
";
//Do a switch and return an integer based on the character.
//The default case gives 0.
switch($Trailing_char)
{
case "9":
return 9;
break;
case "8":
return 8;
break;
case "7":
return 7;
break;
case "6":
return 6;
break;
case "5":
return 5;
break;
case "4":
return 4;
break;
case "3":
return 3;
break;
case "2":
return 2;
break;
case "1":
return 1;
break;
default:
return 0;
break;
}
}
//Decommanates an integer and removes all other crap without respect for
//whether the commas are in the right place or the integer is syntactically valid.
function miller_rabin_decommanate(&$arg)
{
$temp = "";
$len = strlen($arg);
for ($i=0; $i<$len; $i++)
{
$c = (string)Substr($arg, $i, 1);
if (miller_rabin_isdigit($c) || ($c == "-"))
$temp = $temp . $c;
}
$arg = (string)$temp;
}
//Commanates an integer which is assumed to by syntactically correct.
function miller_rabin_commanate(&$arg)
{
miller_rabin_decommanate($arg);
$temp = "";
$len = strlen($arg);
for ($i=0; $i<$len; $i++)
{
$c = (string)Substr($arg, $len - $i - 1, 1);
$temp = $c . $temp;
if ($i != ($len-1))
{
if (Substr($arg, $len-$i-2, 1) != "-")
{
if (($i % 3) == 2)
$temp = "," . $temp;
}
}
}
$arg = (string)$temp;
}
function do_header(&$style, $miller_rabin_nrounds)
{
$style->header_title("Probable Primality Test (Miller-Rabin)",
"Miller-Rabin Probable Primality Test",
"This utility uses " . $miller_rabin_nrounds . " applications of the " .
"" .
"Miller-Rabin test to determine " .
"with high probabilistic certainty whether an integer " .
"is " .
"prime or " .
"composite." .
" This utility does not " .
"factor composite numbers.");
}
function do_footer(&$style)
{
$style->hrule_std();
echo "
This utility is powered by the "; echo ". All source code is available "; echo "here.
\n"; $style->footer_std(); } function do_form($N_refresh, $Buttontext, $max_digits) { echo "\n"; } function do_err_msg($Err_msg) { echo ""; echo $Err_msg; echo "
\n"; } //Main script begins here. // // //Let's agree on a maximum for number of digits in the number to test. It is known that //Apache won't process URL's larger than 1024, so let's be conservative and say 500 //digits. $max_digits = 500; // //Let's agree on a number of rounds for the Miller-Rabin test. This influences the //probabilities. $miller_rabin_nrounds = 25; // //We need to establish the probability that a number which passes the rounds specified //above is still in fact composite. This values need to be calculated by hand whenever //the value above is changed. $miller_rabin_p_real = "0.99999999999999911182"; $miller_rabin_p_percent = "99.999999999999911182"; $miller_rabin_residual_real = "0.00000000000000088818"; $miller_rabin_residual_percent = "0.000000000000088818"; $miller_rabin_residual_lt_reciprocal = "1,125,899,906,842,624"; // $style = new Stdnwpstyle; //Assign the current style in force. Also, starts the CPU //usage clock. //Do the header unconditionally. The header is always used on this page. do_header($style, $miller_rabin_nrounds); // // //If N was supplied, decommanate it and be sure it is a string. if (isset($N)) miller_rabin_decommanate($N); // //There are a few cases to break into here, and this affects the overall layout of the page. //The header and footer are fixed, but the "guts" will change. if (!isset($N)) { //In this case, we are probably visiting the form for the first time, and have not done a submit. //Just display the form itself. do_form("", "Is This Prime?", $max_digits); } elseif (!miller_rabin_issimpleint($N)) { do_err_msg("N is a malformed integer. Choose a new value for N and try again."); $style->hrule_std(); miller_rabin_commanate($N); do_form($N, "Is This Prime?", $max_digits); } elseif ($N == "1") { do_err_msg("It is not a valid question to ask if 1 is prime. It is agreed " . "in number theory (largely to minimize exception cases in proofs and results) " . "that 1 is neither prime nor composite. " . "Choose a new value for N and try again."); $style->hrule_std(); miller_rabin_commanate($N); do_form($N, "Is This Prime?", $max_digits); } elseif (strlen($N) > $max_digits) { do_err_msg("N is too long (a " . number_format($max_digits) . "-digit maximum is " . "in effect). Choose a shorter value and try again."); $style->hrule_std(); miller_rabin_commanate($N); do_form($N, "Is This Prime?", $max_digits); } else { //N seems to be a valid integer. // //If N is negative, make it positive. if (Substr($N, 0, 1)=="-") $N = Substr($N, 1, strlen($N)-1); //If N is "0", make it "2". if ($N=="0") $N = (string)"2"; //We can now run the external program to do the calculation. $cgi_command_string = "./arith_large_cgi gmp_prob_prime " . $N . " " . $miller_rabin_nrounds; //echo "CGI command string is : " . $cgi_command_string . "The integer "; echo $cgi_result[1]; echo " is definitely (with 100% certainty) composite. Note, however, that although "; echo "it was relatively computationally inexpensive to determine that this integer is composite, "; echo "factoring it may be computationally much more expensive.
\n"; } elseif ($cgi_result[3] == 1) { echo "Based on " . $miller_rabin_nrounds . " applications of "; echo "the Miller-Rabin test, the integer "; echo $cgi_result[1]; echo " is probably (with " . $miller_rabin_p_percent . "% certainty) "; echo "prime. (This means that there is no more than 1 chance in "; echo $miller_rabin_residual_lt_reciprocal . " that this integer is "; echo "composite.)
\n"; } else { echo "The integer "; echo $cgi_result[1]; echo " is prime (with 100% certainty). This means that the "; echo "GMP"; echo " library routine was able to attempt trial division with divisors "; echo "up to floor(sqrt(N)).
\n"; } $style->hrule_std(); ?>Notes on the algorithm: