2009-06-25 8 views
10

¿Hay alguna función que devuelva el valor aproximado de n th prime? Creo que esto sería algo así como una función aproximada de recuento de primos inversos. Por ejemplo, si diera esta función 25, devolvería un número alrededor de 100, o si le diera a esta función 1000, devolvería un número alrededor de 8000. No me importa si el número devuelto es primo o no, pero sí quiero que sea rápido (por lo que no la generación de los primeros números n primos para devolver el º n.)¿Hay alguna manera de encontrar el valor aproximado de la enésima prima?

me gustaría este modo que pueda generar los primeros números n primos, usando un tamiz (Eratosthenes o Atkin). Por lo tanto, la aproximación para n th idealmente, nunca subestimaría el valor real de n th prime.

(Actualización: ver my answer para un buen método para encontrar el límite superior de la n número primo t.)

+0

acaba de hacer su tamiz segmentado. y, definitivamente, Eratosthenes. –

+0

http://en.wikipedia.org/wiki/Prime_number_theorem#Approximations_for_the_nth_prime_number – drdaeman

Respuesta

11

límites más estrechos:

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); 
} 

Estos no deben nunca ser inferior a la nth_prime real, debería funcionar para cualquier entrada de 64 bits, y ser de un orden de magnitud o más cerca que la fórmula de Robin dado anteriormente (o la fórmula complicada de rango limitado de Wimblik). Para mi uso, tengo una tabla de primos pequeños un poco más grande, así que puedo ajustar un poco más la última estimación. Técnicamente, a partir de las fórmulas podríamos usar floor() en lugar de ceil() pero me preocupa la precisión.

Editar: Otra opción para mejorar esto un poco es implementar buenos límites de recuento de primos (por ejemplo, Axler 2014) y hacer una búsqueda binaria en ellos. Mi código para este método tarda ~ 10 veces más que lo anterior (aún se ejecuta en menos de un milisegundo), pero puede reducir el porcentaje de error en un orden de magnitud.

Si desea una estimación para el primer enésima, que puede hacer:

  • Cipolla 1902 (ver Dusart 1999 la página 12 o this paper encuentro tres términos (m = 2), además de un factor de corrección de tercer orden a. ser útil, pero con más términos oscila demasiado.La fórmula que se muestra en el enlace de Wikipedia es esta fórmula (con m = 2) .Utilizar los dos términos inversa li o inversa Riemann R a continuación dará mejores resultados.
  • Calcular los límites superiores e inferiores de Dusart 2010 y el promedio de los resultados. No está mal, aunque sospecho que usar un promedio ponderado funcionará mejor ya que los límites no son igualmente ajustados.
  • li^{- 1} (n) Dado que li (n) es una aproximación decente al recuento de primos, el inverso es una aproximación decente nth_prime. Esto, y todo lo demás, se puede hacer bastante rápido como una búsqueda binaria en la función.
  • li^{- 1} (n) + li^{- 1} (sqrt (n))/4 Más cerca, ya que se está acercando a R (n)
  • R^{- 1} Lo inverso La función R de Riemann es la aproximación promedio más cercana que sé que es razonable.

Por último, si tiene un método de recuento de primos muy rápido, como una de las implementaciones de LMO (ahora hay tres implementaciones de código abierto), puede escribir un método nth_prime preciso rápido. La computación de la 10 ° 10 primo se puede hacer en unos pocos milisegundos, y la 10^13 en un par de segundos (en una máquina rápida moderna). Las aproximaciones son extremadamente rápidas en todos los tamaños y funcionan para números mucho mayores, pero todos tienen una idea diferente de lo que significa "grande".

+0

Esta es la mejor respuesta, pero creo que hay un pequeño error. La declaración 'flogn = log (flogn);' probablemente debería ser 'flog2n = log (flogn);' –

+0

@GregS, ¡gracias! Fijo. También agregué un párrafo sobre el uso del recuento de recuento inverso inverso. – DanaJ

4

Prime number theorem da una serie de números primos por debajo de un valor umbral, por lo que podrían ser utilizados para dar un valor aproximado para el enésimo primo.

4

Como estimación aproximada, puede usar n * ln (n) como una aproximación para el enésimo número primo. Existe un método mucho más complejo pero más preciso, cuyos detalles puede encontrar en la Wikipedia here.

0

Una implementación eficiente probablemente no sea posible con un tamiz. Piensa qué pasaría si quieres tener los primeros 10.000 números primos. Probablemente tendrías que hacer un cribado sobre una gran cantidad de números.

Su propia implementación en this question y my answer son buenas formas de implementar esto sin conocer el programa. valor de un primer

8

Gracias por todas esas respuestas. Sospeché que había algo así de simple, pero no pude encontrarlo en ese momento. He hecho un poco más de investigación también.

Como lo quiero para un sieve para generar los primeros números primos n, quiero que la aproximación sea mayor que o igual a la n º primo. (Por lo tanto, quiero que el límite superior de la n número primo t.)

Wikipedia da el límite siguiente superior para n >= 6

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

donde p_n es el n º prime, y log es el logaritmo natural. Este es un buen comienzo, pero puede sobreestimar en una cantidad no despreciable.This article en The College Mathematics Journal da un salto más apretado superior para n >= 7022

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

Ésta es una forma mucho más estricta obligado como la siguiente tabla muestra

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 

implementé mi n función primera aproximación º utilizar la segunda aproximación para n >= 7022, la primera aproximación para 6 <= n < 7022, y una búsqueda de matriz para los primeros 5 números primos.

(Aunque el primer método no es un límite muy estricto, especialmente para el rango en el que lo uso, no me preocupa porque quiero un tamiz, y un tamiz de números más pequeños es computacionalmente barato.)

+4

Desafortunadamente, esta fórmula parece estar rota. 'p_8597' = 88789, pero la fórmula da 88759.3, que es un _underestimate_. Parece que puede estar bien para n> = 8602. – Charphacy

+0

Qué peculiar. Esa fórmula viene directamente de [este documento] (http://mathdl.maa.org/images/cms_upload/jaroma03200545640.pdf), que a su vez se basa en [este documento francés] (http://matwbn.icm.edu .pl/ksiazki/aa/aa42/aa4242.pdf) ... –

+1

De revisar los números primos hasta 2e9 obtuve: 'p_8621 = 89009, p ∈ [88746.2, 89014.4], delta ∈ [-0.9718, -0.9407]' Al elegir 8621 obtienes la aproximación algo mejor usando la constante -0.9407. La siguiente mejora es 'p_15957'. Sí, el papel debe estar equivocado. – starblue

1

mi mejor Prime (n) Estimació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)))))) 

Ésta es mi más reciente fórmula más experimental. por cierto. La primicia diez billones es 323,780,508,946,331 esta fórmula funciona bastante bien en esa escala, no estoy seguro si continúa acercándose a 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))))))) 
0

Para complementar el límite superior de Dana J, esta fórmula debería darle un buen límite inferior.

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; 
Cuestiones relacionadas