Fórmula de teste de primazia

30

Seu objetivo é determinar se um determinado número né primo no menor número de bytes. Mas, seu código deve ser uma única expressão Python 2 em números que consistem em apenas

  • operadores
  • a variável de entrada n
  • constantes inteiras
  • parênteses

Sem loops, sem atribuições, sem funções internas, apenas o que está listado acima. Sim é possivel.

Operadores

Aqui está uma lista de todos os operadores no Python 2 , que incluem operadores aritméticos, bit a bit e 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 os valores intermediários são números inteiros (ou Falso / Verdadeiro, que implicitamente são iguais a 0 e 1). A exponenciação não pode ser usada com expoentes negativos, pois isso pode produzir flutuações. Observe que /a divisão de piso, diferentemente do Python 3, //não é necessária.

Mesmo se você não estiver familiarizado com o Python, os operadores devem ser bastante intuitivos. Consulte esta tabela para obter precedência do operador e esta seção e abaixo para obter uma especificação detalhada da gramática. Você pode executar o Python 2 no TIO .

I / O

Entrada: um número inteiro positivo nque é pelo menos 2.

Saída: 1 se nfor primo e 0 caso contrário. Truee Falsetambém pode ser usado. Menos bytes ganha.

Como seu código é uma expressão, ele será um trecho, esperando o valor de entrada armazenado como ne avaliando a saída desejada.

Seu código deve funcionar para nlimites arbitrariamente grandes do sistema. Como o tipo de número inteiro do Python é ilimitado, não há limites para os operadores. Seu código pode demorar, no entanto, para ser executado.

xnor
fonte
Talvez isso deva ter a tag python?
fənɛtɪk

Respostas:

35

43 bytes

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

Experimente online!

O método é semelhante à segunda resposta (excluída) de Dennis, mas é mais fácil provar que está correta.

Prova

Forma curta

O dígito mais significativo da (4**n+1)**n%4**n**2base que não é divisível por n fará com que o próximo dígito (menos significativo) seja diferente de zero (se esse "dígito seguinte" não estiver na parte fracionária), então um com a máscara de bit é executado para verificar se qualquer dígito na posição ímpar for diferente de zero.2nn(4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n

Forma longa

Seja o número com essa representação base b , ou seja, a n b n + + a 1 b 1 + a 0 b 0 e a i seja o dígito em " posição " i na representação da 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 (comn2n-1s) é um número inteiro e2n2n×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

Em seguida, considere

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

, portanto, truncará o número para 2 n últimos dígitos - que exclui o ( n4n2=(2n)2n%4**n**22n (que é 1), mas inclui todos os outros coeficientes binomiais.(nn)

Sobre /n:

  • Se for primo, o resultado será [ ( nn. Todos os dígitos na posição ímpar são zero.[(nn1)/n,0,,0,(n1)/n,0,0]2n

  • Se não for primo:n

    Seja o maior número inteiro, de modo que n ( na (n>a>0). Reescreva o 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

    O primeiro somatório possui todos os dígitos divisíveis por , e o dígito na posição 2 a - 1 zero.n2a1

    O segundo somatório possui seu dígito mais significativo (na posição ) não divisível por n e (a base) 2 n > n ; portanto, o quociente ao dividir isso por n teria o dígito na posição 2 a - 1 diferente de zero.2an2n>nn2a1

    Portanto, o resultado final ( (4**n+1)**n%4**n**2/n) deve ter o dígito (base , é claro) na posição 2 a + 1 diferente de zero.2n2a+1

Finalmente, o AND bit a bit &executa um AND vetorizado bit a bit nos dígitos da base (porque a base é uma potência de 2) e porque a & 0 = 0 , a & ( 2 n - 1 ) = a para todos 0 a < 2 n , é zero se tiver todos os dígitos nas primeiras n posições ímpares zero - o que equivale a n ser 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

user202729
fonte
2
Funcionaria (4**n+1)**n%2**n**2/n&2**n**2/-~2**n<1?
Dennis
11
Se é fácil provar que está correto, você poderia incluir a prova na resposta? Agora temos o MathJax, portanto é relativamente fácil tornar as provas legíveis e não vejo uma razão óbvia para a divisão por nnão causar interações indesejadas entre a base de dígitos 4**n.
Peter Taylor
3
"Descobri uma prova verdadeiramente notável desta resposta, que esse comentário é muito pequeno para conter ..."
Digital Trauma
1
Sugestões para encurtar a prova são bem-vindas.
user202729
1
Bem feito! Esta é a mesma solução que eu tinha encontrado. Eu achei que alguns bytes podem ser cortados com (4**n+1)**n%4**n**2/n<<n&4**n**2/-~2**n<1. Estou curioso para saber se esse desafio é possível sem 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

Experimente online!

Esta é uma prova de conceito de que este desafio é factível apenas com operadores aritméticos, em particular, sem bit a bit |, &ou ^. O código usa operadores bit a bit e de comparação apenas para jogar golfe, e eles podem ser facilmente substituídos por equivalentes aritméticos.

No entanto, a solução é extremamente lenta e não consegui executar `, graças a expoentes de dois níveis, como 2 n n .n=62nn

A idéia principal é fazer uma expressão para o fatorial , o que nos permite fazer um teste de primalidade do teorema de Wilson ( n - 1 ) ! % n > n - 2 onde % é o operador de módulo.n!(n1)!%n>n2%

Podemos fazer uma expressão para o coeficiente binomial , que é feito de fatoriais

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

Mas não está claro como extrair apenas um desses fatoriais. O truque é separar fazendo m realmente enorme.n!m

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

c(11m)(12m)(1n1m)

n!=mn(mn)c

If we could just ignore c, we'd be done. The rest of this post is looking how large we need to make m to be able to do this.

Note that c approaches 1 from below as m. We just need to make m huge enough that omitting c gives us a value with integer part n! so that we may compute

n!=mn(mn)

For this, it suffices to have 1c<1/n! to avoid the ratio passing the next integer n!+1.

Observe that c is a product of n terms of which the smallest is (1n1m). So, we have

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
fonte
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
fonte
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