is_gaussian_prime (z)?


23

Compito

Scrivi una funzione che accetta due numeri interi a,bche rappresentano il numero intero gaussiano z = a+ib(numero complesso). Il programma deve restituire vero o falso a seconda che a+ibsi tratti di un primo gaussiano o meno .

Definizione:

a + bi è un numero primo gaussiano se e solo se soddisfa una delle seguenti condizioni:

  • ae bsono entrambi diversi da zero ed a^2 + b^2è primo
  • aè zero, |b|è primo e|b| = 3 (mod 4)
  • bè zero, |a|è primo e|a| = 3 (mod 4)

Dettagli

Dovresti solo scrivere una funzione. Se la tua lingua non ha funzioni, puoi presumere che i numeri interi siano memorizzati in due variabili e stampare il risultato o scriverlo in un file.

Non puoi utilizzare le funzioni integrate della tua lingua come isprimeo prime_listo nthprimeo factor. Vince il numero più basso di byte. Il programma deve funzionare per a,bdovea^2+b^2 è un 32bit (firmato) intero e dovrebbe finire in non in modo significativo più di 30 secondi.

Elenco Prime

I punti rappresentano i numeri primi sul piano gaussiano ( x= reale, y= asse immaginario):

inserisci qui la descrizione dell'immagine

Alcuni numeri primi più grandi:

(9940, 43833)
(4190, 42741)
(9557, 41412)
(1437, 44090)

2
Ci è permesso usare le funzioni di fattorizzazione ( factorin Bash, mfe mFin CJam, ...)

Oh no, ho dimenticato che esistevano quei metodi di factoring, no per favore no =) E il limite a 32 bit si applica a a ^ 2 + b ^ 2, altrimenti non avrebbe senso. Grazie per i tuoi input! Ho aggiornato la domanda.
Flawr,

2
Ho aggiunto una definizione di numeri primi gaussiani al post. Se non ti piace come l'ho fatto, sentiti libero di ripristinarlo, ma ti consiglio vivamente di includere la definizione da qualche parte.
undergroundmonorail,

È bello, inizialmente non volevo sottolineare direttamente come determinare la primalità affinché le persone diventassero creative =)
diventassero

1 1073741857 non mi sembra un numero primo gaussiano perché 1 ^ 2 + 1073741857 ^ 2 è un numero pari ...
RosLuP

Risposte:


4

Haskell - 77/ 108 107 Chars

utilizzo: in entrambe le soluzioni, digitare a% b restituirà se a + bi è un primo gaussiano.

il più basso che ho gestito, ma nessuna creatività o prestazione (77 caratteri)

p n=all(\x->rem n x>0)[2..n-1]
a%0=rem a 4==3&&p(abs a)
0%a=a%0
a%b=p$a^2+b^2

questa soluzione fornisce semplicemente tutti i numeri sotto n per verificare se è un numero primo.

versione non golfata:

isprime = all (\x -> rem n x != 0) [2..n-1] -- none of the numbers between 2 and n-1 divide n.
isGaussianPrime a 0 = rem a 4==3 && isprime (abs a)
isGaussianPrime 0 a = isGaussianPrime a 0   -- the definition is symmetric
isGaussianPrime a b = isprime (a^2 + b^2)

la prossima soluzione ha una funzione extra: la memoizzazione. una volta verificato se un numero intero n è primo, non sarà necessario ricalcolare la "primitudine" di tutti i numeri più piccoli o uguali a n, poiché verranno memorizzati nel computer.

(107 caratteri. I commenti sono per chiarezza)

s(p:x)=p:s[n|n<-x,rem n p>0] --the sieve function
l=s[2..]                     --infinite list of primes
p n=n==filter(>=n)l!!0       --check whether n is in the list of primes
a%0=rem a 4==3&&p(abs a)
0%a=a%0
a%b=p$a*a+b*b

versione non golfata:

primes = sieve [2..] where
    sieve (p:xs) = p:filter (\n -> rem n p /= 0) xs
isprime n = n == head (filter (>=n) primes) -- checks if the first prime >= n is equal to n. if it is, n is prime.
isGaussianPrime a 0 = rem a 4==3 && isprime (abs a)
isGaussianPrime 0 a = isGaussianPrime a 0   -- the definition is symmetric
isGaussianPrime a b = isprime (a^2 + b^2)

questo usa il setaccio di Eratostene per calcolare un elenco infinito di tutti i numeri primi (chiamato l per elenco nel codice). (le liste infinite sono un noto trucco di haskell).

come è possibile avere un elenco infinito? all'inizio del programma, l'elenco non è valutato e, invece di archiviare gli elementi degli elenchi, il computer memorizza il modo di calcolarli. ma poiché il programma accede all'elenco, si valuta parzialmente fino alla richiesta. quindi, se il programma richiedesse il quarto elemento nell'elenco, il computer calcolerebbe tutti i numeri primi fino a quel momento che non sono già stati valutati, li memorizzerebbe e gli altri rimarrebbero non valutati, memorizzati come il modo di calcolarli una volta necessario.

si noti che tutto ciò è dato liberamente dalla natura pigra del linguaggio Haskell, nulla di tutto ciò è evidente dal codice stesso.

entrambe le versioni del programma sono sovraccaricate, quindi possono gestire dati di dimensioni arbitrarie.


Secondo il mio conteggio, la tua prima soluzione è in realtà 77 caratteri: D
killmous

ho contato newline, non dovrei?
orgoglioso haskeller il

Conto 74 personaggi regolari e 3
newline

hai ragione, sembra che per qualche motivo notepad ++ aggiunga caratteri prima di newline. Grazie!
orgoglioso haskeller il

ecco perché uso sublime;) felice di aiutarti!
killmous

9

C, 149 118 caratteri

Versione modificata (118 caratteri):

int G(int a,int b){a=abs(a);b=abs(b);int n=a*b?a*a+b*b:a+b,
d=2;for(;n/d/d&&n%d;d++);return n/d/d|n<2?0:(a+b&3)>2|a*b;}

Questa è una singola funzione:

  • G ( a , b ) restituisce un valore diverso da zero (vero) se a + bi è un primo gaussiano o zero (falso) in caso contrario.

Piega il test di primalità sull'intero in un'espressione n/d/d|n<2nascosta nel calcolo del valore restituito. Questo codice golfizzato utilizza anche a*bcome sostituto a&&b(in altre parole a!=0 && b!=0) e altri trucchi che coinvolgono la precedenza dell'operatore e la divisione dei numeri interi. Ad esempio n/d/dè un modo più breve di dire n/d/d>=1, che è un modo di dire sicuro n>=d*do troppo pieno d*d<=no in sostanza d<=sqrt(n).


Versione originale (149 caratteri):

int Q(int n){int d=2;for(;n/d/d&&n%d;d++);return n/d/d||n<2;}
int G(int a,int b){a=abs(a);b=abs(b);return!((a|b%4<3|Q(b))*(b|a%4<3|Q(a))*Q(a*a+b*b));}

funzioni:

  • Q ( n ) restituisce 0 (falso) se n è primo, o 1 (vero) se n è nonprime. È una funzione di aiuto per G ( a , b ).

  • G ( a , b ) restituisce 1 (vero) se a + bi è un primo gaussiano o 0 (falso) in caso contrario.

Output del campione (aumentato del 200%) per | a |, | b | ≤ 128:

Sample128


2
+1 per l'immagine! Potresti anche fare uno delle stesse dimensioni solo nel primo quadrante (perché simmetria), qui sembra davvero fantastico =)
flawr

Puoi salvare un paio di caratteri sostituendo d = 2; per (; n / d / d && n% d; d ++); con for (d = 2; n / d / d && n% d ++;);
Alchymist

@Alchymist - Questo effettivamente salva i caratteri, ma produce risultati errati. È importante che d++ciò non accada come parte della condizione, altrimenti confonde la logica che segue. Inoltre, spostare l' d=2interno del forloop aumenta effettivamente il conteggio dei personaggi anziché diminuirlo, perché ddeve ancora essere dichiarato come intprecedente al forloop. Mi sto perdendo qualcosa?
Todd Lehman,

Troppo vero. Pericoli di guardare questo lontano da un ambiente di codifica e non abbastanza da vicino. L'incremento deve rimanere dove si trova e l'inizializzazione aiuta solo la soluzione originale. Ci sono ovvi risparmi se dichiari n & d al di fuori della funzione, senza specificare int, e inizializzali nel ciclo for ma suppongo che tu stia rendendo la funzione autonoma che è una rigorosa interpretazione dei requisiti.
Alchymist,

1
Il circuito dei primi test qui è un golf spettacolare! Tuttavia è possibile ottenere ancora più risparmi eliminando gli identificatori di tipo int per il tipo e gli argomenti di ritorno, usando una variabile per | a | + | b | e ottimizzando la dichiarazione di ritorno: G(a,b){int s=abs(a)+abs(b),n=a*b?a*a+b*b:s,d=2;for(;n/d/d&&n%d;d++);return n>1>n/d/d&&s%4/3|a*b;}arriva a soli 97 caratteri.
feersum

4

APL (Dyalog Unicode) , 36 47 48 49 47 43 28 byte

Accetta una matrice di due numeri interi a be restituisce il valore booleano dell'istruzione a+bi is a Gaussian integer.

Modifica: +11 byte perché ho frainteso la definizione di un primo gaussiano. +1 byte dalla correzione della risposta di nuovo. +1 byte da una terza correzione di bug. -2 byte dovuti all'uso di un treno anziché di un dfn. -4 byte grazie a ngn a causa dell'utilizzo di una protezione condition: if_true ⋄ if_falseanziché if_true⊣⍣condition⊢if_false. -15 byte grazie a ngn grazie alla ricerca di un modo completamente diverso di scrivere la condizione if-else come un treno completo.

{2=≢∪⍵∨⍳⍵}|+.×0∘∊⊃|{⍺⍵}3=4||

Provalo online!

Spiegazione

{2=≢∪⍵∨⍳⍵}|+.×0∘∊⊃|{⍺⍵}3=4||

                           |   abs(a), abs(b) or abs(list)
                       3=4|    Check if a and b are congruent to 3 (mod 4)
                  |{⍺⍵}        Combine with (abs(a), abs(b))
              0∘∊⊃             Pick out the original abs(list) if both are non-zero
                               Else pick out (if 3 mod 4)
          |+.×                 Dot product with abs(list) returns any of
                               - All zeroes if neither check passed
                               - The zero and the number that IS 3 mod 4
                               - a^2 + b^2
{2=≢∪⍵∨⍳⍵}                     Check if any of the above are prime, and return

3

Haskell - 121 caratteri (newline incluse)

Ecco una soluzione Haskell relativamente semplice che non utilizza alcun modulo esterno ed è ridotta al minimo.

a%1=[]
a%n|n`mod`a<1=a:2%(n`div`a)|1>0=(a+1)%n
0#b=2%d==[d]&&d`mod`4==3where d=abs(b)
a#0=0#a
a#b=2%c==[c]where c=a^2+b^2

Richiamare come ghci ./gprimes.hse quindi è possibile utilizzarlo nella shell interattiva. Nota: i numeri negativi sono pignoli e devono essere inseriti tra parentesi. ie

*Main>1#1
True
*Main>(-3)#0
True
*Main>2#2
False

3

Python - 121 120 caratteri

def p(x,s=2):
 while s*s<=abs(x):yield x%s;s+=1
f=lambda a,b:(all(p(a*a+b*b))if b else f(b,a))if a else(b%4>2)&all(p(b))

pcontrolla se abs(x)è primo ripetendo tutti i numeri da 2 a abs(x)**.5(che è sqrt(abs(x))). Lo fa cedendo x % sper ciascuno s. allquindi controlla se tutti i valori prodotti sono diversi da zero e smette di generare valori quando incontra un divisore di x. In f, f(b,a)sostituisce il caso di b==0, ispirato dalla risposta Haskell di @killmous .


-1 carattere e correzione di bug da @PeterTaylor


Sono contento di
poterti

Potresti sostituirlo s<abs(x)**.5con s*s<abs(x)per un risparmio di 2. Anche se davvero dovresti controllare <=, quindi probabilmente è difettoso al momento.
Peter Taylor,

@PeterTaylor Grazie per aver segnalato il bug ...
hlt

Chiamare i f(0,15)rendimenti TypeError: unsupported operand type(s) for &: 'bool' and 'generator'con il mio interprete. :(
Falko,

f(0,15)Falseper me, sia su 2.7.6 e 3.4.1 (su OS X). Su che versione sei?
hlt

3

Python 2.7 , 341 301 253 byte, ottimizzato per la velocità

lambda x,y:(x==0and g(y))or(y==0and g(x))or(x*y and p(x*x+y*y))
def p(n,r=[2]):a=lambda n:r+range(r[-1],int(n**.5)+1);r+=[i for i in a(n)if all(i%j for j in a(i))]if n>r[-1]**2else[];return all(n%i for i in r if i*i<n)
g=lambda x:abs(x)%4>2and p(abs(x))

Provalo online!

#pRimes. need at least one for r[-1]
r=[2]
#list of primes and other to-check-for-primarity numbers 
#(between max(r) and sqrt(n))
a=lambda n:r+list(range(r[-1],int(n**.5)+1))
#is_prime, using a(n)
f=lambda n:all(n%i for i in a(n))
#is_prime, using r
def p(n):
    global r
    #if r is not enough, update r
    if n>r[-1]**2:
        r+=[i for i in a(n) if f(i)]
    return all(n%i for i in r if i*i<n)
#sub-function for testing (0,y) and (x,0)
g=lambda x:abs(x)%4==3 and p(abs(x))
#the testing function
h=lambda x,y:(x==0 and g(y)) or (y==0 and g(x)) or (x and y and p(x*x+y*y))

Grazie: 40 +48 - tutto il golf a Jo King


Anche la flambda non è obbligatoria, insieme alla listchiamata. 257 byte senza quelli, oltre a qualche rimozione degli spazi bianchi. Questo forse non è più così efficace, però
Jo King il

(15,0) è ora vero nella versione da 257 byte e il tempo di esecuzione è aumentato anche di 5,5 secondi, scusa
Alexey Burdin

2

Perl - 110 107 105 caratteri

Spero di aver seguito correttamente la definizione collegata ...

sub f{($a,$b)=map abs,@_;$n=$a**(1+!!$b)+$b**(1+!!$a);(grep{$n%$_<1}2..$n)<2&&($a||$b%4>2)&&($b||$a%4>2)}

Ungolfed:

sub f {
  ($a,$b) = map abs, @_;
  $n = $a**(1+!!$b) + $b**(1+!!$a);
  (grep {$n%$_<1} 2..$n)<2 && ($a || $b%4==3) && ($b || $a%4==3)
}

Spiegazione, perché qualcuno ha chiesto: ho letto gli argomenti ( @_) e mettere i loro valori assoluti in $a, $b, perché la funzione non ha bisogno di loro segno. Ciascuno dei criteri richiede di testare la primalità di un numero, ma questo numero dipende dal fatto $ache siano o meno $bzero, cosa che ho cercato di esprimere nel modo più breve possibile e di inserirlo $n. Infine controllo se $nè primo contando quanti numeri tra 2 e se stesso lo dividono senza resto (questa è la grep...<2parte), quindi controllo inoltre che se uno dei numeri è zero, l'altro è uguale a 3 modulo 4. La funzione è il valore di ritorno è di default il valore della sua ultima riga e queste condizioni restituiscono un valore di verità se tutte le condizioni sono state soddisfatte.


Non riesco a farlo funzionare per parametri negativi.
killmous

1
@killmous hai ragione, l'ho appena risolto
Tal

potresti spiegare l'algoritmo?
orgoglioso haskeller il

1
Bello! A proposito, penso che potresti radere un paio di personaggi scrivendo $a%4>2invece di $a%4==3.
Todd Lehman,

2

golflua 147 141

Il conteggio sopra trascura le nuove righe che ho aggiunto per vedere le diverse funzioni. Nonostante l'insistenza di non farlo, risolvo con forza bruta i numeri primi all'interno dei casi.

\p(x)s=2@s*s<=M.a(x)?(x%s==0)~0$s=s+1$~1$
\g(a,b)?a*b!=0~p(a^2+b^2)??a==0~p(b)+M.a(b)%4>2??b==0~p(a)+M.a(a)%4>2!?~0$$
w(g(tn(I.r()),tn(I.r())))

Restituisce 1 se vero e 0 se no.

Una versione Lua ungolfed,

-- prime number checker
function p(x)
   s=2
   while s*s<=math.abs(x) do
      if(x%s==0) then return 0 end
      s=s+1
   end
   return 1
end

-- check gaussian primes
function g(a,b)
   if a*b~=0 then
      return p(a^2+b^2)
   elseif a==0 then
      return p(b) + math.abs(b)%4>2
   elseif b==0 then
      return p(a) + math.abs(a)%4>2
   else
      return 0
   end
end


a=tonumber(io.read())
b=tonumber(io.read())
print(g(a,b))

Puoi salvare 6 personaggi semplicemente collegandoli tonumber(io.read())come argomento alla gfine, e altri 2 rimuovendo le nuove righe
mniip

@mniip: le nuove righe non sono state contate, ho appena aggiunto quelle per chiarezza (senza scorrimento laterale). Aggiornerò la lettura in g quando inizierò a lavorare tra poco. Grazie!
Kyle Kanos,

Bene funziona ancora in un ragionevole lasso di tempo per grandi numeri? Ho pensato principalmente al bruteforcing nel modo di controllare tutti gli interi gaussiani adove |a| <= |z|if a | z(se adivide z).
Flawr

@flawr: l'ho provato con a = 2147483644, b = 896234511 e ho ottenuto 0 in circa 0,002 s. L'ho anche testato con 2147483629 e 2147483587 (due numeri primi molto grandi) e ho ottenuto 0 in altri 0,002 s. Sto cercando di trovare una grande coppia di numeri in modo tale che a ^ 2 + b ^ 2 sia un numero primo e mi assicuri di avere una soluzione funzionante per numeri così grandi.
Kyle Kanos,

@flawr: testato con a = 4600 & b = 5603 (a ^ 2 + b ^ 2 = 2147393609 è primo e <2 ^ 32-1) e ci sono voluti gli stessi 0,002 secondi per restituire 1. Yay!
Kyle Kanos,

1

APL (NARS), 99 caratteri, 198 byte

r←p w;i;k
r←0⋄→0×⍳w<2⋄i←2⋄k←√w⋄→3
→0×⍳0=i∣w⋄i+←1
→2×⍳i≤k
r←1

f←{v←√k←+/2*⍨⍺⍵⋄0=⍺×⍵:(p v)∧3=4∣v⋄p k}

test:

  0 f 13
0
  0 f 9
0
  2 f 3
1
  3 f 4
0
  0 f 7
1
  0 f 9
0
  4600 f 5603
1  

1

Incantesimi runici , 41 byte

>ii:0)?\S:0)?\:*S:*+'PA@
3%4A|'S/;$=?4/?3

Provalo online!

Alla fine è stato molto più facile di quanto pensassi e non c'era molto spazio per la golfificazione. Il programma originale che ho bloccato era:

>ii:0)?\S:0)?\:*S:*+'PA@
3%4A|'S/!   S/;$=

Ho giocato con il tentativo di confrontare entrambi gli input contemporaneamente (che ha salvato tutto di 1 byte), ma quando quello scende nella sezione "uno di questi è zero", non c'era un buon modo per capire quale elemento era diverso da zero per eseguire l'ultimo controllo, tanto meno un modo per farlo senza spendere almeno 1 byte (nessun risparmio complessivo).


1

Mathematica, 149 personaggi

If[a==0,#[[3]]&&Mod[Abs@b,4]==3,If[b==0,#[[2]]&&Mod[Abs@a,4]==3,#[[1]]]]&[(q=#;Total[Boole@IntegerQ[q/#]&/@Range@q]<3&&q!=0)&/@{a^2+b^2,Abs@a,Abs@b}]

Il codice non utilizza alcuna funzione standard di numeri primi di matematica, ma conta il numero di numeri interi nell'elenco {n / 1, n / 2, ..., n / n}; se il numero è 1 o 2, allora n è primo. Una forma elaborata della funzione:

MyIsPrime[p_] := (q = Abs@p; 
  Total[Boole@IntegerQ[q/#] & /@ Range@q] < 3 && q != 0)

Trama bonus di tutti i Primes gaussiani da -20 a 20:

Trama di numeri primi gaussiani


1

Rubino -rprime , 65 60 80 byte

Non ho notato la regola "impossibile utilizzare isPrime" ...

->a,b{r=->n{(2...n).all?{|i|n%i>0}};c=(a+b).abs;r[a*a+b*b]||a*b==0&&r[c]&&c%4>2}

Provalo online!


0

Python - 117 122 121

def f(a,b):
 v=(a**2+b**2,a+b)[a*b==0]
 for i in range(2,abs(v)):
  if v%i<1:a=b=0
 return abs((a,b)[a==0])%4==3or a*b!=0

Poiché 3 è il numero più grande che un numero può essere mod 4, è possibile sostituire il ==3con>2
FlipTack
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.