Сгенерировать большое простое число с указанными последними цифрами

Интересно, как можно генерировать 512-битное (155 десятичных цифр) простое число, последние пять десятичных цифр которого указаны/исправлены (например, *** 28071)??

Принципы генерации простых простых чисел без каких-либо спецификаций вполне понятны, но мой случай идет дальше.

Любые подсказки, по крайней мере, с чего начать?

Предпочтительнее использовать Java или С#.

Спасибо!

Ответ 1

Я предполагаю, что единственный способ - сначала создать случайное число из 150 десятичных цифр, а затем добавить 28071 за ним, выполнив number = randomnumber * 100000 + 28071, а затем просто перетащить его с помощью чего-то вроде

while (!IsPrime(number))
    number += 100000;

Конечно, это может занять некоторое время, чтобы вычислить; -)

Ответ 2

Вы пытались просто генерировать такие цифры и проверять их? Я ожидал бы, что это будет приемлемо быстро. Основная плотность уменьшается только как логарифм числа, поэтому я ожидаю, что вы попробуете несколько сотен номеров, пока не нажмете премьер. ln(2^512) = 354, поэтому примерно одно число в 350 будет простым.

Грубо говоря, теорема о простых числах гласит, что если выбрано случайное число, близкое к некоторому большому числу N, вероятность его простого составляет около 1/ln (N), где ln (N) обозначает натуральный логарифм N Например, около N = 10000, примерно одно из девяти чисел является простым, тогда как около N = 1,000,000,000, только один из каждых 21 чисел является простым. Другими словами, средний разрыв между простыми числами вблизи N примерно равен ln (N)

(из http://en.wikipedia.org/wiki/Prime_number_theorem)

Вам просто нужно позаботиться о том, чтобы число было для ваших окончательных цифр. Но я считаю, что так же легко проверить, что последняя цифра не делится на 2 или 5 (то есть 1, 3, 7 или 9).

Согласно данным производительности, вы можете сделать около 2000 операций ModPow с 512-битными данными в секунду, а так как простой простой тест проверяя 2^(p-1) mod p=1, которая является одной операцией ModPow, вы должны иметь возможность генерировать несколько простых чисел со своими свойствами в секунду.

Итак, вы можете сделать (псевдокод):

BigInteger FindPrimeCandidate(int lastDigits)
{
    BigInteger i=Random512BitInt;
    int remainder = i % 100000;
    int increment = lastDigits-remainder;
    i += increment;
    BigInteger test = BigInteger.ModPow(2, i - 1, i);
    if(test == 1)
      return i;
    else
      return null;
}

И сделайте более обширные первичные проверки результата этой функции.

Ответ 3

Как сказал @Doggot, но начинайте с наименее возможного 150-значного числа, которое заканчивается 28071, означает 100000.... 0028071, теперь добавляйте его по 100000 каждый раз и для тестирования в первую очередь используйте мельник-рабин, как и код, который я предоставил здесь, он нуждается в некоторой настройке. Если возвращаемое значение истинно, сначала проверьте его на точное.

Ответ 4

Вы можете использовать сито, которое содержит только числа, удовлетворяющие вашему специальному условию, для фильтрации чисел, делящихся на маленькие простые числа.

Для каждого малого простого p вам нужно найти правильную отправную точку и шаг, учитывая, что в сите присутствует только 100000-й номер.

Для чисел, оставшихся в сите, вы можете использовать BigInteger.isProbablePrime(), чтобы проверить, является ли оно простым с достаточной вероятностью.

Ответ 5

Пусть ABCDE будет пятизначным числом в базе десять, которое вы рассматриваете. На основе , если ABCDE и 100000 взаимно просты, то существует бесконечно много простых чисел вида 100000 * k + ABCDE. Поскольку вы ищете простые числа, ни 2, ни 5 не разделили бы ABCDE в любом случае, таким образом ABCDE и 100000 будут взаимно просты. Таким образом, существует бесконечно множество простых чисел формы, которые вы рассматриваете.

Ответ 6

Вы можете расширить один из стандартных методов для создания больших простых чисел, добавив дополнительное ограничение, то есть последние 5 десятичных цифр должны быть правильными, Наивно, вы можете просто добавить это как дополнительный тест, но это увеличит время, чтобы найти подходящее правое число на 10 ^ 5.

Не так наивно: сгенерировать случайное 512-битное число, а затем установить достаточные младшие биты, чтобы десятичное представление заканчивалось требуемой последовательностью. Затем продолжайте обычные тесты на примитивность.

Ответ 7

Давайте рассмотрим грубую силу. Взгляните на этот очень интересный текст под названием "Лотерея с простым номером":

Учитывая последнюю запись в последней таблице, существует ~ 2.79 * 10 ^ 14 простых чисел менее 10 ^ 16. Таким образом, примерно каждое 35-е число является простым в этом диапазоне.

EDIT: см. комментарий от CodeInChaos - если вы просто пройдете несколько тысяч 512-битных чисел с фиксированными 5-значными цифрами, вы найдете их быстро.

Ответ 8

Я переписал алгоритм грубой силы из мира int в BigDecimal один с помощью класса BigSquareRoot из http://www.merriampark.com/bigsqrt.htm. (Обратите внимание, что от 1 до 1000 говорят, что это точно 168 простых чисел.)

Извините, но если вы разместите там свой диапазон, то есть < 10 154; 10 155 -1 > , вы можете позволить своему компьютеру работать, и когда вы уйдете на пенсию, вы можете получить результат... это чертовски медленно!

Однако вы можете как-то найти хотя бы часть этого полезного в сочетании с другими ответами в этом потоке.


package edu.eli.test.primes;

import java.math.BigDecimal;

public class PrimeNumbersGenerator {

  public static void main(String[] args) {
//    BigDecimal lowerLimit = BigDecimal.valueOf(10).pow(154); /* 155 digits */
//    BigDecimal upperLimit = BigDecimal.valueOf(10).pow(155).subtract(BigDecimal.ONE);

    BigDecimal lowerLimit = BigDecimal.ONE;
    BigDecimal upperLimit = new BigDecimal("1000");

    BigDecimal prime = lowerLimit;
    int i = 1;

    /* http://www.merriampark.com/bigsqrt.htm */
    BigSquareRoot bsr = new BigSquareRoot();
    upperLimit = upperLimit.add(BigDecimal.ONE);
    while (prime.compareTo(upperLimit) == -1) {

      bsr.setScale(0);
      BigDecimal roundedSqrt = bsr.get(prime);

      boolean isPrimeNumber = false;
      BigDecimal upper = roundedSqrt;
      while (upper.compareTo(BigDecimal.ONE) == 1) {

        BigDecimal div = prime.remainder(upper);
        if ((prime.compareTo(upper) != 0) && (div.compareTo(BigDecimal.ZERO) == 0)) {
          isPrimeNumber = false;
          break;
        } else if (!isPrimeNumber) {
          isPrimeNumber = true;
        }

        upper = upper.subtract(BigDecimal.ONE);
      }

      if (isPrimeNumber) {
        System.out.println("\n" + i + " -> " + prime + " is a prime!");
        i++;
      } else {
        System.out.print(".");
      }
      prime = prime.add(BigDecimal.ONE);
    }
  }

}