Я пишу программу, чтобы продемонстрировать тестирование вероятности Миллера-Рабина на Java. Код в значительной степени сделан...
import java.util.Random;
import java.util.Scanner;
/**
* Program to demonstrate Miller-Rabin primality testing
*
* @author Nick Gilbert
*/
public class MillerRabin
{
public static void main(String[] args)
{
//Setting up for algorithm
Scanner in = new Scanner(System.in);
Random rn = new Random();
int n = 0, k = 0, m = 0, a = 0;
double b = 0;
boolean probablyPrime = false;
//Asking user for an odd n
do
{
System.out.print("Enter an odd number to test for primality: ");
n = in.nextInt();
}
while(n % 2 == 0);
//Calculating k and m
m = n - 1;
while(m % 2 == 0)
{
m /= 2;
k++;
}
//Generating random a
//a = rn.nextInt(n-1);
//Outputting numbers that will be used in algorithm
System.out.println("k = " + k);
System.out.println("m = " + m);
System.out.println();
a = 86;
System.out.println("A = " + a);
//Running the algorithm
//b_{0}
b = Math.pow(a, m) % n;
System.out.println("b0 = " + b);
if(Math.abs(b) == Math.abs(1 % n)) //Dealing with +/- case via absolute value
{
probablyPrime = true;
}
else
{
//b_{1-(k-1)}
for(int i = 1; i < k; i++) //Going to k-1
{
b = Math.pow(b, 2) % n;
System.out.println("b" + i + " = " + b);
if(Math.abs(b) == Math.abs(1 % n)) //Dealing with +/- case via absolute value
{
probablyPrime = true;
break;
}
}
}
//Printing result
if(probablyPrime)
{
System.out.println("Probably Prime");
}
else
{
System.out.println("Definitely Composite");
}
}
}
Я был жестко закодирован 86, так как мне важно продемонстрировать свою проблему. Где он вычисляет b в первый раз, поднимая a до m и принимая модуль n, математика неверна. Вместо того, чтобы давать b0 из 86, что является правильным ответом на 86 ^ 19% 153, он дает мне b0 равно 107. Я проверил свои значения в отладчике, и они правы. Я также проверил значение a ^ m, и это дает мне 86 ^ 19, поэтому проблема возникает с частью модуля. К сожалению, я не знаю, что отбрасывает математику.
double
точность в Java (и любая система IEEE) имеет только 15-16 цифр точности. Если вы используете число, которое больше этого, вы получите ошибку представления.
Скорее всего, вам нужно использовать BigInteger, который не только обрабатывает произвольную точность, но и оптимизирован для мощности и модуля.
// 86^19 % 153
BigInteger result = BigInteger.valueOf(86).modPow(BigInteger.valueOf(19), BigInteger.valueOf(153));
System.out.println(result);
печать
86
pow
, а только конечный результат. Вы можете попробовать это для больших показателей, и время, затрачиваемое на это, довольно постоянное.
Здесь Math.pow возвращает double, поэтому получение модуля double не поможет (никогда не принимайте Mod на двойнике, никто не несет ответственности за то, что вы получаете).
и заметим, что (89 ^ 19) составляет примерно 2 ^ 122, поэтому беззнаковое длинное (2 ^ 64-1) не будет удерживать это число. и double имеет точность 2 ^ 53 (никогда не используйте double to mod, теория чисел находится на целых числах). Используйте меньшее значение или используйте класс BigInteger.
Примитивные типы данных имеют заданные размеры, которые могут ограничить их точность.
Java имеет класс BigInteger, который может работать для вашего сценария.
1 % n
? Это выглядит немного подозрительно для меня.