Fórmula de prueba de primalidad

30

Su objetivo es determinar si un número dado nes primo en la menor cantidad de bytes. Pero, su código debe ser una sola expresión de Python 2 en números que consisten solo en

  • operadores
  • la variable de entrada n
  • constantes enteras
  • paréntesis

Sin bucles, sin asignaciones, sin funciones integradas, solo lo que se menciona anteriormente. Si es posible.

Operadores

Aquí hay una lista de todos los operadores en Python 2 , que incluye operadores aritméticos, bit a bit y lógicos:

+    adddition
-    minus or unary negation
*    multiplication
**   exponentiation, only with non-negative exponent
/    floor division
%    modulo
<<   bit shift left
>>   bit shift right
&    bitwise and
|    bitwise or
^    bitwise xor
~    bitwise not
<    less than
>    greater than
<=   less than or equals
>=   greater than or equals
==   equals
!=   does not equal

Todos los valores intermedios son enteros (o Falso / Verdadero, que implícitamente es igual a 0 y 1). La exponenciación no puede usarse con exponentes negativos, ya que esto puede producir flotadores. Tenga en cuenta que /hace la división del piso, a diferencia de Python 3, por //lo que no es necesario.

Incluso si no está familiarizado con Python, los operadores deberían ser bastante intuitivos. Vea esta tabla para la precedencia del operador y esta sección y más abajo para una especificación detallada de la gramática. Puede ejecutar Python 2 en TIO .

I / O

Entrada: Un entero positivo nque es al menos 2.

Salida: 1 si nes primo y 0 en caso contrario. Truey Falsetambién se puede usar. Pocos bytes ganan.

Como su código es una expresión, será un fragmento, esperando el valor de entrada almacenado como ny evaluando el resultado deseado.

Su código debe funcionar para narbitrariamente grandes, dejando a un lado los límites del sistema. Como el tipo de número entero de Python no tiene límites, no hay límites para los operadores. Su código puede tardar mucho tiempo en ejecutarse.

xnor
fuente
Tal vez esto debería tener la etiqueta python?
fəˈnɛtɪk

Respuestas:

35

43 bytes

(4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n<1

Pruébalo en línea!

El método es similar a la segunda respuesta (eliminada) de Dennis, pero es más fácil demostrar que esta respuesta es correcta.

Prueba

Forma corta

El dígito más significativo de (4**n+1)**n%4**n**2en base que no es divisible entre n hará que el siguiente dígito (menos significativo) sea distinto de cero (si ese "siguiente dígito" no está en la parte fraccionaria), se ejecuta a con la máscara de bits para verificar si algún dígito en la posición impar no es cero.2nn(4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n

Forma larga

Sea el número que tiene esa representación base b , es decir, a n b n + + a 1 b 1 + a 0 b 0 , y a i es el dígito en " posición " i en representación de base b .[an,,a1,a0]bbanbn++a1b1+a0b0aiib

  • .2**(2*n*n+n)/-~2**n=2(2n+1)n1+2n=4n2×2n1+2n=(4n21)×2n1+2n+2n1+2n

Porque (conn2n-1s) es un número entero, y2n2n×4n211+2n=2n(2n1)×(4n)n14n1=[2n1,0,2n1,0,2n1,0]2nn 2n1, =[2n-1,0,2n-1,0,2n-1,0]2n.2n1+2n=02**(2*n*n+n)/-~2**n[2n1,0,2n1,0,2n1,0]2n

A continuación, considere

(4**n+1)**n=(4n+1)n=(n0)40n+(n1)41n++(nn)4n2=[(nn),0,,0,(n1),0,(n0)]2n

, porlo que truncará el número a 2 n últimos dígitos, lo que excluye el ( n4n2=(2n)2n%4**n**22n (que es 1) pero incluye todos los demás coeficientes binomiales.(nn)

Acerca de /n:

  • Si es primo, el resultado será [ ( nn. Todos los dígitos en la posición impar son cero.[(nn1)/n,0,,0,(n1)/n,0,0]2n

  • Si no es primo:n

    Sea el mayor número entero tal que n ( na (n>a>0). Reescribe el dividendo comon(na)n>a>0

    [(nn1),0,(nn2),0,,(na+1),0,0,0,,0,0,0]2n+[(na),0,(na1),0,,(n0)]2n

    El primer sumando tiene todos los dígitos divisibles por , y el dígito en la posición 2 a - 1 cero.n2a1

    El segundo sumando tiene su dígito más significativo (en la posición ) no divisible por ny (la base) 2 n > n , por lo que el cociente al dividir eso entre n tendría el dígito en la posición 2 a - 1 distinto de cero.2an2n>nn2a1

    Por lo tanto, el resultado final ( (4**n+1)**n%4**n**2/n) debe tener el dígito (base , por supuesto) en la posición 2 a + 1 diferente de cero.2n2a+1

Finalmente, el AND a nivel de bits ( &) realiza un AND a nivel de bits vectorizado en los dígitos en la base (porque la base es una potencia de 2), y porque a & 0 = 0 , a & ( 2 n - 1 ) = a para todos 0 a < 2 n , es cero si f tiene todos los dígitos en las primeras n posiciones impares cero, lo que equivale a n siendo primo.2na&0=0,a&(2n1)=a0a<2n(4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n(4**n+1)**n%4**n**2/nnn

usuario202729
fuente
2
Funcionaria (4**n+1)**n%2**n**2/n&2**n**2/-~2**n<1?
Dennis
11
Si es fácil demostrar que es correcto, ¿podría incluir la prueba en la respuesta? Tenemos MathJax ahora, por lo que es relativamente fácil hacer legibles las pruebas, y no puedo ver una razón obvia para la división al nno causar interacciones no deseadas entre la base de dígitos 4**n.
Peter Taylor
3
"He descubierto una prueba verdaderamente notable de esta respuesta que este comentario es demasiado pequeño para contener ..."
Digital Trauma
1
Las sugerencias para acortar la prueba son bienvenidas.
user202729
1
¡Bien hecho! Esta es la misma solución que se me ocurrió. Encontré que se pueden cortar un par de bytes (4**n+1)**n%4**n**2/n<<n&4**n**2/-~2**n<1. Tengo curiosidad por saber si este desafío es posible sin operadores bit a bit.
xnor
6

Python 2 , 56 bytes

n**(n*n-n)/(((2**n**n+1)**n**n>>n**n*~-n)%2**n**n)%n>n-2

Pruébalo en línea!

Esta es una prueba de concepto que este desafío es factible con sólo los operadores aritméticos, en particular, sin bit a bit |, &o ^. El código usa operadores bit a bit y de comparación solo para jugar al golf, y pueden reemplazarse fácilmente con equivalentes aritméticos.

Sin embargo, la solución es extremadamente lenta, y no he podido ejecutar ', gracias a exponentes de dos niveles como 2 n n .n=62nn

La idea principal es hacer una expresión para el factorial , Lo que nos permite hacer un teorema de Wilson test de primalidad ( n - 1 ) ! % n > n - 2 donde % es el operador del módulo.n!(n1)!%n>n2%

Podemos hacer una expresión para el coeficiente binomial , que está hecho de factoriales

(mn) =m!n!(mn)!

Pero no está claro cómo extraer solo uno de estos factoriales. El truco es martillar aparte haciendo m realmente grande.n!m

(mn) =m(m1)(mn+1)n!=mnn!(11m)(12m)(1n1m)

Entonces, si dejamos que sea ​​el producto ( 1 - 1c, tenemos(11m)(12m)(1n1m)

n!=mn(mn)c

Si pudiéramos ignorar , estaríamos listos. El resto de esta publicación analiza qué tan grande debemos hacer m para poder hacer esto.cm

Tenga en cuenta que aproxima a 1 desde abajo como m . ¡Solo necesitamos hacer m lo suficientemente grande como para que omitir c nos dé un valor con la parte entera n ! para que podamos calcularc1mmcn!

n!=mn(mn)

Para esto, es suficiente tener para evitar que la relación pase el siguiente entero n1c<1/n!n!+1

Observe que es un producto de n términos de los cuales el más pequeño es ( 1 -cn(1n1m)

c>(1n1m)n>1n1mn>1n2m,

which means 1c<n2m. Since we're looking to have 1c<1/n!, it suffices to take mn!n2.

In the code, we use m=nn. Since Wilson's Theorem uses (n1)!, we actually only need m(n1)!(n1)2. It's easy to see that m=nn satisfies the bound for the small values and quickly outgrows the right hand side asymptotically, say with Stirling's approximation.

xnor
fuente
3

This answer doesn't use any number-theoretic cleverness. It spams Python's bitwise operators to create a manual "for loop", checking all pairs 1i,j<n to see whether i×j=n.

Python 2, way too many bytes (278 thanks to Jo King in the comments!)

((((((2**(n*n)/(2**n-1)**2)*(2**((n**2)*n)/(2**(n**2)-1)**2))^((n*((2**(n*n-n)/(2**n-1))*(2**((n**2)*(n-1))/(2**n**2-1))))))-((2**(n*n-n)/(2**n-1))*(2**((n**2)*(n-1))/(2**(n**2)-1))))&(((2**(n*(n-1))/(2**n-1))*(2**((n**2)*(n-1))/(2**(n**2)-1)))*(2**(n-1)))==0))|((1<n<6)&(n!=4))

Try it online!

This is a lot more bytes than the other answers, so I'm leaving it ungolfed for now. The code snippet below contains functions and variable assignment for clarity, but substitution turns isPrime(n) into a single Python expression.

def count(k, spacing):
    return 2**(spacing*(k+1))/(2**spacing - 1)**2
def ones(k, spacing):
    return 2**(spacing*k)/(2**spacing - 1)

def isPrime(n):
    x = count(n-1, n)
    y = count(n-1, n**2)
    onebits = ones(n-1, n) * ones(n-1, n**2)
    comparison = n*onebits
    difference = (x*y) ^ (comparison)
    differenceMinusOne = difference - onebits
    checkbits = onebits*(2**(n-1))
    return (differenceMinusOne & checkbits == 0 and n>1)or 1<n<6 and n!=4

Why does it work?

I'll do the same algorithm here in base 10 instead of binary. Look at this neat fraction:

1.09992=1.002003004005

If we put a large power of 10 in the numerator and use Python's floor division, this gives an enumeration of numbers. For example, 1015/(9992)=1002003004 with floor division, enumerating the numbers 1,2,3,4.

Let's say we multiply two numbers like this, with different spacings of zeroes. I'll place commas suggestively in the product.

1002003004×1000000000002000000000003000000000004=
1002003004,002004006008,003006009012,004008012016

The product enumerates, in three-digit sequences, the multiplication table up to 4 times 4. If we want to check whether the number 5 is prime, we just have to check whether 005 appears anywhere in that product.

To do that, we XOR the above product by the number 005005005005, and then subtract the number 001001001001. Call the result d. If 005 appeared in the multiplication table enumeration, it will cause the subtraction to carry over and put 999 in the corresponding place in d.

To test for this overflow, we compute an AND of d and the number 900900900900. The result is zero if and only if 5 is prime.

Lopsy
fuente
1
A quick print of the expression puts this at 278 bytes (though I'm sure a lot of the parenthesises aren't necessary)
Jo King