Есть ли способ найти приблизительное значение n-го простого числа?

Есть ли функция, которая вернет приблизительное значение n -го простого числа? Я думаю, это будет что-то вроде приблизительной функции обратного подсчета простых чисел. Например, если бы я дал этой функции 25, она вернула бы число около 100, или если бы я дал этой функции 1000, она вернула бы число около 8000. Меня не волнует, является ли возвращаемое число простым или нет, но я хочу он должен быть быстрым (поэтому не нужно генерировать первые n простых чисел, чтобы вернуть n th.)

Мне бы хотелось, чтобы я мог сгенерировать первые n простых чисел с помощью сита (Эратосфен или Аткин). Следовательно, приближение для n -го числа в идеале никогда не должно недооценивать значение фактического n -го простого числа.

(Обновление: см. мой ответ о хорошем методе определения верхней границы n -го простого числа.)


person David Johnstone    schedule 25.06.2009    source источник
comment
en.wikipedia.org/wiki/   -  person drdaeman    schedule 25.06.2009
comment
просто сделай свое сито сегментированным. и, безусловно, Эратосфен.   -  person Will Ness    schedule 22.08.2014


Ответы (7)


Более узкие рамки:

static const unsigned short primes_small[] = {0,2,3,5,7,11};

static unsigned long nth_prime_upper(unsigned long n) {
  double fn = (double) n;
  double flogn, flog2n, upper;
  if (n < 6)  return primes_small[n];
  flogn  = log(n);
  flog2n = log(flogn);

  if      (n >= 688383)    /* Dusart 2010 page 2 */
    upper = fn * (flogn + flog2n - 1.0 + ((flog2n-2.00)/flogn));
  else if (n >= 178974)    /* Dusart 2010 page 7 */
    upper = fn * (flogn + flog2n - 1.0 + ((flog2n-1.95)/flogn));
  else if (n >=  39017)    /* Dusart 1999 page 14 */
    upper = fn * (flogn + flog2n - 0.9484);
  else                    /* Modified from Robin 1983 for 6-39016 _only_ */
    upper = fn * ( flogn  +  0.6000 * flog2n );

  if (upper >= (double) ULONG_MAX) {
     /* Adjust this as needed for your type and exception method */
    if (n <= 425656284035217743UL) return 18446744073709551557UL;
    fprintf(stderr, "nth_prime_upper overflow\n"; exit(-1);
  }

  return (unsigned long) ceil(upper);
}

Они никогда не должны быть меньше фактического nth_prime, должны работать для любого 64-битного ввода и быть на порядок или более близкими, чем формула Робина, приведенная ранее (или сложная формула Wimblik с ограниченным диапазоном). Для моего использования у меня есть таблица малых простых чисел немного большего размера, так что я могу немного уточнить последнюю оценку. Технически из формул мы могли бы использовать floor () вместо ceil (), но меня беспокоит точность.

Изменить: Еще один способ немного улучшить это - реализовать хорошие границы количества простых чисел (например, Axler 2014) и выполнить по ним двоичный поиск. Мой код для этого метода занимает примерно в 10 раз больше времени, чем приведенный выше (все еще выполняется менее миллисекунды), но может снизить процент ошибок на порядок.

Если вам нужна оценка n-го простого числа, вы можете сделать:

  • Cipolla 1902 (см. Dusart 1999 стр. 12 или этот документ. Я нашел три термина ( m = 2) плюс поправочный коэффициент третьего порядка, чтобы быть полезным, но с большим количеством членов он слишком сильно колеблется. Формула, показанная в ссылке в Википедии, является этой формулой (с m = 2). Использование двухчленного обратного li или обратного Римана R ниже даст лучшие результаты.
  • Рассчитайте верхнюю и нижнюю границы Dusart 2010 и усредните результаты. Не так уж и плохо, хотя я подозреваю, что использование средневзвешенного значения будет работать лучше, поскольку границы не одинаково жесткие.
  • li ^ {- 1} (n) Так как li (n) - хорошее приближение к числу простых чисел, обратное - хорошее приближение nth_prime. Это и все остальное можно сделать довольно быстро в виде двоичного поиска функции.
  • li ^ {- 1} (n) + li ^ {- 1} (sqrt (n)) / 4 Ближе, так как это приближается к R (n)
  • R ^ {- 1} Обратная функция Римана R - это самое близкое среднее приближение, которое я знаю, что это разумно.

Наконец, если у вас есть очень быстрый метод подсчета простых чисел, такой как одна из реализаций LMO (сейчас есть три реализации с открытым исходным кодом), вы можете написать быстрый точный метод nth_prime. Вычисление 10 ^ 10-го простого числа может быть выполнено за несколько миллисекунд, а 10 ^ 13-го - за пару секунд (на современной быстрой машине). Приближения очень быстрые для всех размеров и работают для гораздо больших чисел, но каждый по-своему понимает, что означает «большой».

person DanaJ    schedule 22.08.2014
comment
Это лучший ответ, но я думаю, что в нем есть небольшая ошибка. Выражение flogn = log(flogn);, вероятно, должно быть flog2n = log(flogn); - person President James K. Polk; 24.12.2014
comment
@GregS, спасибо! Фиксированный. Я также добавил параграф об использовании ограничения обратного числа простых чисел. - person DanaJ; 24.12.2014

Спасибо за все эти ответы. Я подозревал, что это было что-то довольно простое, но в то время я не мог этого найти. Я тоже провел немного больше исследований.

Поскольку я хочу, чтобы сито генерировало первое n < / em> простые числа, я хочу, чтобы приближение было больше или равно n -ому простому числу. (Следовательно, мне нужна верхняя граница n -го простого числа.)

Википедия дает следующую верхнюю границу для n >= 6

p_n <= n log n + n log log n   (1)

где p_n - n -е простое число, а log - натуральный логарифм. Это хорошее начало, но его можно переоценить на немалую сумму. Эта статья в The College Mathematics Journal дает более жесткую верхнюю границу для n >= 7022

p_n <= n log n + n (log log n - 0.9385)   (2)

Это гораздо более жесткая граница, как показано в следующей таблице.

n         p_n         approx 1    error%  approx 2    error%
1         2                            
10        29          31          6.90 
100       541         613         13.31
1000      7919        8840        11.63
10000     104729      114306      9.14    104921      0.18
100000    1299709     1395639     7.38    1301789     0.16
1000000   15485863    16441302    6.17    15502802    0.11
10000000  179424673   188980382   5.33    179595382   0.10

Я реализовал свою функцию n -го простого приближения, чтобы использовать второе приближение для n >= 7022, первое приближение для 6 <= n < 7022 и поиск в массиве для первых 5 простых чисел.

(Хотя первый метод не является очень жестким, особенно для диапазона, в котором я его использую, меня это не волнует, так как я хочу использовать его для сита, а сито с меньшими числами обходится дешево в вычислительном отношении.)

person David Johnstone    schedule 01.07.2009
comment
К сожалению, эта формула не работает. p_8597 = 88789, но формула дает 88759,3, что занижено. Похоже, это нормально для n ›= 8602. - person Charphacy; 18.04.2012
comment
Как странно. Эта формула взята прямо из этого документа, который, в свою очередь, основан на этот французский документ ... - person David Johnstone; 08.04.2013
comment
Проверяя простые числа до 2e9, я получил: p_8621 = 89009, p ∈ [88746.2, 89014.4], delta ∈ [-0.9718, -0.9407] Выбрав 8621, вы получите несколько лучшее приближение с использованием константы -0.9407. Следующее улучшение - p_15957. Да, бумага должна быть неправильной. - person starblue; 12.10.2013
comment
Граница фактически выполняется от n ›39017 в соответствии с Дюссарту: k-е простое число больше k (lnk + lnlnk − 1) для k≥2., Math. Сравн., 68 (225), 411--415. - person G. Bach; 22.11.2014
comment
@DavidJohnstone: Ссылка на статью не работает. Не могли бы вы предоставить обновленную ссылку? - person Gaurav; 14.08.2015
comment
@Gaurav, вот в настоящее время рабочая ссылка на статью «Верхняя граница N-го прайма»: maa.org/sites/default/files/jaroma03200545640.pdf - person I. J. Kennedy; 08.12.2020

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

person Ian Hopkinson    schedule 25.06.2009

В качестве приблизительной оценки вы можете использовать n * ln (n) в качестве приближения для n-го простого числа. Существует гораздо более сложный, но более точный метод, подробности о котором вы можете найти в Википедии здесь < / а>.

person Jon    schedule 25.06.2009

Моя лучшая оценка Prime (n)

1/2*(8-8.7*n-n^2+
1/2*(2*abs(log(n)/log(3)+log(log(n)/log(2))/log(2))+
abs((log(log(3))-log(log(n))+2*n*log(log(n)/log(2))+
sqrt(((8*log(3)*log(n))/log(2)-log(log(2))+
log(log(n)))*log(log(n)/log(2))))/log(log(n)/log(2))))*(-1+
abs(log(n)/log(3)+log(log(n)/log(2))/log(2))+abs(-(1/2)+n+
sqrt(((8*log(3)*log(n))/log(2)-log(log(2))+
log(log(n)))*log(log(n)/log(2)))/(2*log(log(n)/log(2))))))

Вот моя последняя экспериментальная формула. Кстати. Десяти триллионное простое число равно 323,780,508,946,331, эта формула довольно хорошо работает в этом масштабе, не уверен, продолжит ли оно приближаться к n*ln(n)+n*(ln(ln(n))-0.9385).

1/2*(3-(8+ln(2.3))*n-n^2+1/2*(-1+
abs(-(1/2)+n+sqrt(ln(ln(n)/ln(2))*(-ln(ln(2))+ln(ln(n))+
(8*ln(3)*ln((n*ln(8*n))/ln(n)))/ln(2)))/(2*ln(ln((n*ln(8*n))/
ln(n))/ln(2))))+abs(ln(n)/ln(3)+ln(ln((n*ln(8*n))/ln(n))/ln(2))/
ln(2)))*(2*abs(ln((n*ln(8*n))/ln(n))/ln(3)+ln(ln((n*ln(8*n))/ln(n))/
ln(2))/ln(2))+abs(1/ln(ln(n)/ln(2))*(ln(ln(3))-ln(ln(n))+2*n*ln(ln(n)/
ln(2))+sqrt(((8*ln(3)*ln(n))/ln(2)-ln(ln(2))+ln(ln((n*ln(8*n))/ln(n))))*
ln(ln((n*ln(8*n))/ln(n))/ln(2)))))))
person Quoss P Wimblik    schedule 28.02.2012

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

Ваша собственная реализация в этом вопросе и мой ответ - хорошие способы реализовать это, не зная о приложении. стоимость прайма

person Peter Smit    schedule 25.06.2009

Чтобы дополнить верхнюю границу Даны Дж., Эта формула должна дать вам хорошую нижнюю границу.

P(n) = (((2 Log(3, n + 2))/(Log(2.5, 2) + Log(3, 3)) + (2 Log(3, n - 2))/(Log(3, 2) + Log(3, 3)))/2) n;
person AnaloDim Ripe AnaloDimRipe    schedule 21.12.2017