Esta regexp en Perl comprueba si un número es primo o no / Avinash Meetoo
En los últimos meses descubrí un par de curiosidades sobre fórmulas para producir números primos y comprobarlos, entendiendo por «fórmulas» o proporcionadamente una función matemática o proporcionadamente un software sencillo que genera todos los números primos o que comprueba su primalidad.
Ya hace siglos que Euler vio que n² – n + 41 genera toda una serie de números primos… pero sólo entre el 1 y el 40… ¿Sería una serie válida para producir más números primos? Pues no: con n = 41 la fórmula da como resultado 1681 que resulta ser el producto de 41 × 41, poco obvio al examinar la fórmula.
La idea de multiplicar todos los números primos en secuencia y sumarles 1 siquiera sirve. Veamos un ejemplo:
2 × 3 × 5 × 7 × 11 × 13 + 1 = 30031
pero resulta que 30031 = 59 × 509. La idea deja de ser válida porque la multiplicación crece muy rápido y puede tener factores primos por encima de los que se están multiplicando, poco que no se ha tenido en cuenta en la idea innovador.
La fórmula para producir primos de C.P. Williams
¿Es posible que exista una fórmula para producir todos los números primos por su orden? Siempre había audición que teóricamente no existen, y que encontrar «el ulterior número primo» es penoso. Pero resulta que sí que existen… aunque su utilidad como se explica más delante es suficiente discutible. Véase:
Esta es la curiosa fórmula que C.P. Williams publicó en 1964. No es muy complicada de interpretar: el enésimo número primo (pn) es 1 + un sumatorio entre 1 y 2n de una fracción que incluye otro sumatorio con un factorial, un coseno y el número π (¡toma ya!). Se toma el valencia categórico, se hacen unas potencias, una división, alguna cosa más y ¡voilà! Enésimo primo preparado.
El caso es que es dócil probar incluso manualmente algunos títulos pequeños, o programar la fórmula en el ordenador y darle títulos para observar cómo con el 4 genera el 4º número primo (7), o con el 10 el 10º número primo (29). ¿Qué brujería es esta?
Hay un vídeo de primera de Eric Rowland que desglosa cuidadosamente el «funcionamiento» de la fórmula paso a paso para explicar cómo una parte se comporta como «detector de números primos»:
El sumatorio funciona como un tirabuzón entre 1 y el número a probar (el 1+ del principio sirve para que el primer primo sea el 2). Al ir recorriendo la secuencia de los números naturales devuelve títulos 0 ó 1 si el número es primo o no, y en cuyo caso se «anula» ese término para suceder al ulterior, simplemente porque el valencia es cero. Si el tirabuzón se completa es que el número verdaderamente es primo, y se puede dar por bueno. El coseno y π se utilizan virtuosamente para hacer que ciertos títulos de comprobación varíen entre -1 y 1 con distintos significados*.
Pero, ¿cómo sabe si un número cedido es primo? El cálculo viene a funcionar verificando por orden todos los números naturales y respondiendo en tirabuzón a preguntas como «Es el número de primos hasta 2 pequeño que 4?» «Es el número de primos hasta 3 pequeño que 4?» y así sucesivamente para títulos de i, j y n. Muy preparado no es.
Es dócil ver que es terriblemente ineficiente: el sumatorio es entre 1 y 2n, un valencia que crece de forma brutalmente exponencial: para 4 hay que comprobar hasta el 16 pero para 100 ya es casi un gúgol; el otro sumatorio para comprobar la primalidad y el factorial empeoran el panorama. Encima, cada paso requiere recalcular toda la serie de nuevo, poco suficiente insensatez entendido como un «cálculo», aunque esa era su naturaleza, claro.
Hubo cierto debate sobre la esencia de esta fórmula, que se considera «correcta, pero completamente inútil». No explica de donde surgen los números primos y simplemente los va mirando y enumerando como si lo hiciera un escolar de primaria. Pero acierta. Así que ahí queda.
La expresión regular que genera primos (y en solo 18 caracteres)
Esta regexp (expresión regular) de Perl, que todavía funciona en Ruby comprueba si un número es primo o no:
/^1?$|^(11+?)1+$/
¿Puede poco tan escueto factorizar un número y comprobar si es primo o no? Es sabido que las regexp son rebuscadamente crípticas, pero puntada ejecutar un software con un tirabuzón de números naturales y la regexp en cuestión para ver cómo escupe números primos cual oso que caga números primos, sin fallos.
El artículo de Avinash Meetoo destripa la expresión en sus dos partes, ayer y luego de la mostrador enhiesto (|). La primera parte es trivial para eliminar los títulos 0 y 1.
La segunda parte es donde está la chicha, que básicamente consiste en que los números se representan como cadenas de unos, de modo que por ejemplo 8 es 11111111 (ojo: no es binario, son 8 unos). La expresión se comporta de forma recursiva, buscando si la esclavitud es «divisible» por todos los números más bajos, como el 2 (11), el 3 (111), etcétera sin que tras iterar sobre toda la esclavitud sobre cero. Si todas las pruebas fallan, el número no es divisible (o más proporcionadamente «troceable») por nadie más pequeño, de modo que es primo y se muestra como tal.
Este método todavía es tremendamente cachazudo, e incluso en ordenadores modernos más allá de 1 millón se ejecuta a velocidad de tortuga, pero funcionar, funciona.
Hay más detalles y alguna que otra curiosidad extra en el foro de Hacker News donde Meetoo envió su idea, incluyendo versiones similares en otros lenguajes y el debate sobre cuán válidas (o faltas de practicidad) son estos ingeniosos pero inútiles algoritmos.
_____
* Este método de usar trigonometría, títulos absolutos y sumatorios a modo de bucles tiene muchas aplicaciones en otros algoritmos informáticos, si se puede hacer de forma efectivo; es una especie de conversión analógica-digital de títulos muy distintos a binarios (sí/no) suficiente curiosa.