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

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

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

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

Java или C# предпочтительнее.

спасибо!

8 ответов


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

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

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


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

грубо говоря, теорема о простых числах гласит, что если выбрано случайное число вблизи некоторого большого числа N, вероятность того, что оно простое, составляет около 1 / ln(N), где ln (N) обозначает естественный логарифм N. например, около N = 10,000, около одного из девяти чисел является простым, тогда как около 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;
}

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


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


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

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

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


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


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

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


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

Извините, но если вы поместите туда свой диапазон, то есть 154; 10155-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);
    }
  }

}


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

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

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