Formula di test di primalità


30

Il tuo obiettivo è determinare se un determinato numero nè primo nel minor numero di byte. Ma il tuo codice deve essere una singola espressione di Python 2 su numeri costituiti solo da

  • operatori
  • la variabile di input n
  • costanti intere
  • parentesi

Nessun loop, nessuna assegnazione, nessuna funzione integrata, solo ciò che è elencato sopra. Si è possibile.

operatori

Ecco un elenco di tutti gli operatori in Python 2 , che includono operatori aritmetici, bit a bit e logici:

+    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

Tutti i valori intermedi sono numeri interi (o False / True, che implicitamente è uguale a 0 e 1). L'esponenziazione non può essere usata con esponenti negativi, poiché ciò può produrre galleggianti. Nota che /fa la divisione del pavimento, a differenza di Python 3, quindi //non è necessario.

Anche se non hai familiarità con Python, gli operatori dovrebbero essere piuttosto intuitivi. Vedi questa tabella per la precedenza degli operatori e questa sezione e sotto per una specifica dettagliata della grammatica. È possibile eseguire Python 2 su TIO .

I / O

Input: un numero intero positivo nche è almeno 2.

Uscita: 1 se nè primo e 0 altrimenti. Truee Falsepuò anche essere usato. Vince il minor numero di byte.

Poiché il codice è un'espressione, sarà uno snippet, in attesa del valore di input archiviato come ne valutato sull'output desiderato.

Il codice deve funzionare a parte narbitrariamente, limiti di sistema a parte. Poiché il tipo di numero intero di Python è illimitato, non ci sono limiti per gli operatori. L'esecuzione del codice potrebbe richiedere molto tempo.


Forse questo dovrebbe avere il tag Python?
fəˈnɛtɪk,

Risposte:


35

43 byte

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

Provalo online!

Il metodo è simile alla seconda risposta (eliminata) di Dennis, ma questa risposta è più facile da dimostrare corretta.

Prova

Forma breve

La cifra più significativa di (4**n+1)**n%4**n**2in base che non è divisibile per n renderà la cifra successiva (meno significativa) in diverso da zero (se quella "cifra successiva" non è nella parte frazionaria), quindi viene eseguito un segno con la maschera di bit per verificare se qualsiasi cifra in posizione dispari è diversa da zero.2nn(4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n

Forma lunga

Sia il numero avente quella rappresentazione di base b , ovvero a a n b n + + a 1 b 1 + a 0 b 0 e a i sia la cifra in " posizione " i nella rappresentazione di 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

Perché (con2n×4n211+2n=2n(2n1)×(4n)n14n1=[2n1,0,2n1,0,2n1,0]2n2 n - 1 s) è un numero intero e2 nn 2n1, =[2n-1,0,2n2n1+2n=02**(2*n*n+n)/-~2**n .[2n1,0,2n1,0,2n1,0]2n

Quindi, considera

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

4n2=(2n)2n , quindi %4**n**2troncerà il numero su ultime cifre - che esclude il ( n2n (che è 1) ma include tutti gli altri coefficienti binomiali.(nn)

Circa /n:

  • Se n è un numero primo, il risultato sarà . Tutte le cifre in posizione dispari sono zero.[(nn1)/n,0,,0,(n1)/n,0,0]2n

  • Se non è un numero primo:n

    Lascia a il numero intero più grande tale che n(na) ( ). Riscrivi il dividendo comen>a>0

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

    Il primo summand ha tutte le cifre divisibili per e il numero nella posizione 2 a - 1 zero.n2a1

    Il secondo summand ha la sua cifra più significativa (nella posizione ) non divisibile per n e (la base) 2 n > n , quindi il quoziente quando lo divide per2an2n>n avrebbe la cifra nella posizione 2 a - 1 diversa da zero.n2a1

    Pertanto, il risultato finale ( (4**n+1)**n%4**n**2/n) dovrebbe avere la cifra (base , ovviamente) in posizione 2 a + 1 diversa da zero.2n2a+1

Infine, AND bit a bit ( &) esegue un AND bit a bit vettoriale sulle cifre in base (perché la base è una potenza di 2) e perché a & 0 = 0 , a & ( 2 n - 1 ) = a per tutti 0 a < 2 n , è zero sef ha tutte le cifre nelle prime n posizioni dispari zero - che equivale a n che è 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


2
Funzionerebbe (4**n+1)**n%2**n**2/n&2**n**2/-~2**n<1?
Dennis,

11
Se è facile dimostrare che è corretto, potresti includere la prova nella risposta? Ora abbiamo MathJax, quindi è relativamente facile rendere leggibili le prove e non riesco a vedere una ragione ovvia per la divisione per nnon causare interazioni indesiderate tra la base delle cifre 4**n.
Peter Taylor,

3
"Ho scoperto una prova davvero notevole di questa risposta che questo commento è troppo piccolo per contenere ..."
Digital Trauma,

1
Suggerimenti per accorciare la prova sono ben accetti.
user202729

1
Ben fatto! Questa è la stessa soluzione che avevo escogitato. Ho scoperto che è possibile tagliare un paio di byte (4**n+1)**n%4**n**2/n<<n&4**n**2/-~2**n<1. Sono curioso di sapere se questa sfida è possibile senza operatori bit per bit.
xnor

6

Python 2 , 56 byte

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

Provalo online!

Si tratta di un proof-of-concept che questa sfida è fattibile solo con gli operatori aritmetici, in particolare senza bit per bit |, &o ^. Il codice utilizza bit per bit e operatori di confronto solo per il golf e possono essere facilmente sostituiti con equivalenti aritmetici.

Tuttavia, la soluzione è estremamente lenta e non sono stato in grado di eseguire `, grazie a esponenti a due livelli come 2 n nn=62nn .

L'idea principale è quella di creare un'espressione per il fattoriale , che ci permette di fare un test di primalità sul teorema di Wilson ( n - 1 ) ! % n > n - 2 dove % è l'operatore modulo.n!(n1)!%n>n2%

Possiamo fare un'espressione per il coefficiente binomiale , che è fatto di fattoriali

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

Ma non è chiaro come estrarre solo uno di questi fattoriali. Il trucco è smontarerendendo m davvero enorme.n!m

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

c be the product (11m)(12m)(1n1m), we have

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.


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.


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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.