Нечетная математическая ошибка в Java

1

Я пишу программу, чтобы продемонстрировать тестирование вероятности Миллера-Рабина на 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, поэтому проблема возникает с частью модуля. К сожалению, я не знаю, что отбрасывает математику.

  • 2
    Можете ли вы объяснить, что вы ожидаете от 1 % n ? Это выглядит немного подозрительно для меня.
  • 0
    Это не то, где моя проблема, значение b является неправильным, прежде чем он даже достигнет этой точки
Показать ещё 2 комментария
Теги:
primes
primality-test

3 ответа

2

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
  • 0
    Мне было просто любопытно, использует ли этот метод modPow модульное возведение в степень?
  • 0
    @TamimAdDari Этот метод оптимизирован так, что он фактически не вычисляет часть pow , а только конечный результат. Вы можете попробовать это для больших показателей, и время, затрачиваемое на это, довольно постоянное.
1

Здесь Math.pow возвращает double, поэтому получение модуля double не поможет (никогда не принимайте Mod на двойнике, никто не несет ответственности за то, что вы получаете).

и заметим, что (89 ^ 19) составляет примерно 2 ^ 122, поэтому беззнаковое длинное (2 ^ 64-1) не будет удерживать это число. и double имеет точность 2 ^ 53 (никогда не используйте double to mod, теория чисел находится на целых числах). Используйте меньшее значение или используйте класс BigInteger.

  • 0
    Double имеет точность только 2 ^ 53, так как старшие биты используются для знака и показателя степени.
  • 0
    @ Питер, ты прав.
0

Примитивные типы данных имеют заданные размеры, которые могут ограничить их точность.

Java имеет класс BigInteger, который может работать для вашего сценария.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню