is_gaussian_prime (z)?

23

Tâche

Écrivez une fonction qui accepte deux entiers a,bqui représentent l'entier gaussien z = a+ib(nombre complexe). Le programme doit retourner vrai ou faux selon qu'il a+ibs'agit d'un nombre premier gaussien ou non .

Définition:

a + bi est un nombre premier gaussien si et seulement s'il remplit l'une des conditions suivantes:

  • aet bsont à la fois non nul et a^2 + b^2est premier
  • aest zéro, |b|est premier et|b| = 3 (mod 4)
  • best zéro, |a|est premier et|a| = 3 (mod 4)

Détails

Vous ne devez écrire qu'une fonction. Si votre langue n'a pas de fonctions, vous pouvez supposer que les entiers sont stockés dans deux variables et imprimer le résultat ou l'écrire dans un fichier.

Vous ne pouvez pas utiliser les fonctions intégrées de votre langue comme isprimeou prime_listou nthprimeou factor. Le plus petit nombre d'octets gagne. Le programme doit fonctionner pour a,ba^2+b^2est un entier 32 bits (signé) et doit se terminer en pas plus de 30 secondes.

Liste principale

Les points représentent des nombres premiers sur le plan gaussien ( x= réel, y= axe imaginaire):

entrez la description de l'image ici

Quelques nombres premiers plus grands:

(9940, 43833)
(4190, 42741)
(9557, 41412)
(1437, 44090)
flawr
la source
2
Sommes-nous autorisés à utiliser les fonctions de factorisation ( factordans Bash, mfet mFdans CJam, ...)
Oh non, j'ai oublié que ces méthodes de factorisation existaient, non s'il vous plaît pas =) Et la limite de 32 bits s'applique à un ^ 2 + b ^ 2, n'aurait pas de sens autrement. Merci pour vos contributions! J'ai mis à jour la question.
flawr
2
J'ai ajouté une définition des nombres premiers gaussiens au message. Si vous n'aimez pas la façon dont je l'ai fait, n'hésitez pas à revenir en arrière, mais je recommanderais certainement d'inclure la définition quelque part.
undergroundmonorail
C'est bien, à l'origine, je ne voulais tout simplement pas indiquer directement comment déterminer la primauté pour que les gens deviennent créatifs =)
flawr
1 1073741857 ne me semble pas un nombre premier gaussien car 1 ^ 2 + 1073741857 ^ 2 est un nombre pair ...
RosLuP

Réponses:

4

Haskell - 77/108 107 caractères

utilisation: dans les deux solutions, taper a% b retournera si a + bi est un nombre premier gaussien.

le plus bas que j'ai réussi, mais pas de créativité ni de performance (77 caractères)

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

cette solution passe simplement par tous les nombres en dessous de n pour vérifier s'il est premier.

version non golfée:

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 solution suivante a une fonctionnalité supplémentaire - la mémorisation. une fois que vous avez vérifié si un entier n est premier, vous n'aurez pas besoin de recalculer la "primauté" de tous les nombres inférieurs ou égaux à n, car il sera stocké dans l'ordinateur.

(107 caractères. Les commentaires sont pour plus de clarté)

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

version non golfée:

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)

ceci utilise le tamis d'Eratosthène pour calculer une liste infinie de tous les nombres premiers (appelés l pour liste dans le code). (les listes infinies sont une astuce bien connue de haskell).

comment est-il possible d'avoir une liste infinie? au début du programme, la liste n'est pas évaluée, et au lieu de stocker les éléments des listes, l'ordinateur stocke la façon de les calculer. mais lorsque le programme accède à la liste, il s'évalue partiellement jusqu'à la demande. donc, si le programme demandait le quatrième élément de la liste, l'ordinateur calculerait tous les nombres premiers jusqu'au quatrième qui ne sont pas déjà évalués, les stockerait et le reste resterait non évalué, stocké comme moyen de les calculer une fois nécessaire.

notez que tout cela est donné librement par la nature paresseuse du langage Haskell, rien de cela ne ressort du code lui-même.

les deux versions du programme sont surchargées, de sorte qu'elles peuvent gérer des données de taille arbitraire.

fier haskeller
la source
D'après mes calculs, votre première solution est en fait 77 caractères: D
killmous
j'ai compté les nouvelles lignes, n'est-ce pas?
fier haskeller
Je compte 74 personnages réguliers et 3 nouvelles lignes
killmous
vous avez raison, il semble que pour une raison quelconque le bloc-notes ++ ajoute des caractères avant les nouvelles lignes. Merci!
fier haskeller
c'est pourquoi j'utilise sublime;) heureux de vous aider!
killmous
9

C, 149 118 caractères

Version éditée (118 caractères):

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;}

Il s'agit d'une seule fonction:

  • G ( a , b ) renvoie non nul (vrai) si a + bi est un nombre premier gaussien, ou zéro (faux) sinon.

Il replie le test de primalité entière en une expression n/d/d|n<2cachée dans le calcul de la valeur de retour. Ce code golfé utilise également a*bcomme substitut a&&b(en d'autres termes a!=0 && b!=0) et d'autres astuces impliquant la priorité de l'opérateur et la division entière. Par exemple, n/d/dc'est une façon plus courte de dire n/d/d>=1, qui est une manière sûre de déborder de dire n>=d*dou d*d<=nou essentiellement d<=sqrt(n).


Version originale (149 caractères):

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));}

Les fonctions:

  • Q ( n ) renvoie 0 (faux) si n est premier, ou 1 (vrai) si n n'est pas premier. C'est une fonction d'aide pour G ( a , b ).

  • G ( a , b ) renvoie 1 (vrai) si a + bi est un nombre premier gaussien, ou 0 (faux) sinon.

Exemple de sortie (augmentée de 200%) pour | a |, | b | ≤ 128:

Échantillon128

Todd Lehman
la source
2
+1 pour l'image! Pourriez-vous également en faire un à peu près de la même taille juste dans le premier quadrant (parce que la symétrie), il a vraiment fière allure ici =)
flawr
Vous pouvez enregistrer quelques caractères en remplaçant d = 2; for (; n / d / d && n% d; d ++); avec pour (d = 2; n / d / d && n% d ++;);
Alchymist
@Alchymist - Cela enregistre en effet des caractères, mais produit des résultats incorrects. Il est important que d++cela ne se produise pas dans le cadre de la condition, sinon cela gâche la logique suivante. De plus, déplacer l' d=2intérieur de la forboucle augmente le nombre de caractères plutôt que de le diminuer, car dil doit toujours être déclaré comme intavant la forboucle. Suis-je en train de manquer quelque chose?
Todd Lehman
Trop vrai. Risques de regarder cela loin d'un environnement de codage et pas assez étroitement. L'incrémentation doit rester où elle est et l'initialisation n'aide que votre solution d'origine. Il y a des économies évidentes si vous déclarez n & d en dehors de la fonction, sans spécifier int, et que vous les initialisez dans la boucle for, mais je suppose que vous rendez la fonction autonome, ce qui est une interprétation stricte des exigences.
Alchymist
1
La boucle de test principal est un golf spectaculaire! Cependant, il est possible de réaliser encore plus d'économies en supprimant les spécificateurs de type int pour le type de retour et les arguments, en utilisant une variable pour | a | + | b | et l'optimisation de l'instruction de retour: 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;}sort à seulement 97 caractères.
feersum
4

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

Prend un tableau de deux entiers a bet renvoie la valeur booléenne de l'instruction a+bi is a Gaussian integer.

Edit: +11 octets car j'ai mal compris la définition d'un nombre premier gaussien. +1 octet de correction à nouveau de la réponse. +1 octet d'une troisième correction de bogue. -2 octets dus à l'utilisation d'un train au lieu d'un dfn. -4 octets grâce à ngn en raison de l'utilisation d'un garde condition: if_true ⋄ if_falseau lieu de if_true⊣⍣condition⊢if_false. -15 octets grâce à ngn car il a trouvé une manière complètement différente d'écrire la condition if-else comme un train complet.

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

Essayez-le en ligne!

Explication

{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
Sherlock9
la source
3

Haskell - 121 caractères (nouvelles lignes incluses)

Voici une solution Haskell relativement simple qui n'utilise aucun module externe et qui est autant utilisée que possible.

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

Appelez-le ghci ./gprimes.hset vous pourrez ensuite l'utiliser dans le shell interactif. Remarque: les nombres négatifs sont capricieux et doivent être placés entre parenthèses. C'est à dire

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

Python - 121120 caractères

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

pvérifie si abs(x)est premier en itérant sur tous les nombres de 2 à abs(x)**.5(ce qui est sqrt(abs(x))). Il le fait en cédant x % spour chacun s. allvérifie ensuite si toutes les valeurs fournies sont non nulles et arrête de générer des valeurs une fois qu'il rencontre un diviseur dex . Dans f, f(b,a)remplace le cas de b==0, inspiré par la réponse de @killmous Haskell.


-1 caractère et correction de bogue de bogue @PeterTaylor

hlt
la source
Heureux d'avoir pu aider :)
killmous
Vous pouvez le remplacer s<abs(x)**.5par s*s<abs(x)une économie de 2. Bien que vous devriez vraiment vérifier <=, c'est probablement un buggy pour le moment.
Peter Taylor
@PeterTaylor Merci d'avoir signalé le bug ...
hlt
L'appel f(0,15)cède TypeError: unsupported operand type(s) for &: 'bool' and 'generator'avec mon interprète. :(
Falko
f(0,15)donne Falsepour moi, à la fois sur 2.7.6 et 3.4.1 (sur OS X). Sur quelle version êtes-vous?
hlt
3

Python 2.7 , 341 301 253 octets, optimisé pour la vitesse

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

Essayez-le en ligne!

#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))

Merci: 40 +48 - golf entier à Jo King

Alexey Burdin
la source
Le flambda est également inutile, avec l' listappel. 257 octets sans ceux-ci, plus une suppression des espaces blancs. Mais ce n'est peut-être plus aussi efficace
Jo King
(15,0) est maintenant vrai dans la version 257 octets et le temps d'exécution a également augmenté de 5,5 s, désolé
Alexey Burdin
2

Perl - 110 107 105 caractères

J'espère avoir suivi correctement la définition liée ...

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)}

Non golfé:

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)
}

Explication, parce que quelqu'un a demandé: je lis les arguments ( @_) et de mettre leurs valeurs absolues en $a, $bparce que la fonction n'a pas besoin de leur signe. Chacun des critères nécessite de tester la primalité d'un nombre, mais ce nombre dépend de la valeur zéro $aou non $b, que j'ai essayé d'exprimer de la manière la plus courte et de le mettre $n. Enfin je vérifie si $nest premier en comptant combien de nombres entre 2 et lui-même le divise sans reste (c'est la grep...<2partie), puis vérifie en outre que si l'un des nombres est nul alors l'autre est égal à 3 modulo 4. La fonction est la valeur de retour est par défaut la valeur de sa dernière ligne, et ces conditions renvoient une valeur vraie si toutes les conditions sont remplies.

Tal
la source
Je ne peux pas le faire fonctionner pour les paramètres négatifs.
killmous
1
@killmous vous avez raison, venez de le corriger
Tal
pouvez-vous expliquer l'algorithme?
fier haskeller
1
Agréable! Soit dit en passant, je pense que vous pourriez raser quelques personnages en écrivant à la $a%4>2place de $a%4==3.
Todd Lehman
2

golflua 147 141

Le décompte ci-dessus néglige les nouvelles lignes que j'ai ajoutées pour voir les différentes fonctions. Malgré l'insistance à ne pas le faire, je résous par force brute les nombres premiers dans les cas.

\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())))

Renvoie 1 si vrai et 0 sinon.

Une version Lua non golfée,

-- 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))
Kyle Kanos
la source
Vous pouvez enregistrer 6 caractères en les connectant simplement tonumber(io.read())comme argument à gla fin, et 2 autres en supprimant les nouvelles lignes
mniip
@mniip: les nouvelles lignes n'ont pas été comptées, je viens de les ajouter pour plus de clarté (pas de défilement latéral). Je mettrai à jour la lecture en g lorsque je me mettrai au travail dans un petit moment. Merci!
Kyle Kanos
Eh bien, cela fonctionne-t-il toujours dans un délai raisonnable pour les grands nombres? J'ai principalement pensé au bruteforcing pour vérifier tous les entiers gaussiens a|a| <= |z|if a | z(si adivise z).
flawr
@flawr: Je l'ai testé avec a = 2147483644, b = 896234511 et j'ai obtenu 0 en environ 0,002 s. Je l'ai également testé avec 2147483629 et 2147483587 (deux très grands nombres premiers) et j'ai obtenu 0 dans un autre 0,002 s. J'essaie de trouver une grande paire de nombres tels qu'un ^ 2 + b ^ 2 est premier et je m'assure d'avoir une solution de travail pour de si grands nombres.
Kyle Kanos
@flawr: testé avec a = 4600 & b = 5603 (a ^ 2 + b ^ 2 = 2147393609 est premier & <2 ^ 32-1) et il a fallu les mêmes 0,002 secondes pour renvoyer 1. Yay!
Kyle Kanos
1

APL (NARS), 99 caractères, 198 octets

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}

tester:

  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  
RosLuP
la source
1

Enchantements runiques , 41 octets

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

Essayez-le en ligne!

J'ai fini par être beaucoup plus facile que je ne le pensais et il n'y avait pas beaucoup de place pour la golfification. Le programme original que j'ai bloqué était:

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

J'ai essayé de comparer les deux entrées en même temps (ce qui a sauvé tout d'un octet), mais lorsque cela tombe dans la section "l'une d'entre elles est nulle", il n'y avait pas de bon moyen de déterminer quel élément était non nul pour effectuer le dernier contrôle, et encore moins un moyen de le faire sans dépenser au moins 1 octet (pas d'économies globales).

Draco18s ne fait plus confiance à SE
la source
1

Mathematica, 149 caractères

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}]

Le code n'utilise aucune caractéristique de nombre premier standard de mathématique, au lieu de cela il compte le nombre d'entiers dans la liste {n / 1, n / 2, ..., n / n}; si le nombre est 1 ou 2, alors n est premier. Une forme élaborée de la fonction:

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

Intrigue bonus de tous les Primes gaussiennes de -20 à 20:

Tracé des nombres premiers gaussiens

ralian
la source
1

Rubis -rprime , 65 60 80 octets

Je n'ai pas remarqué la règle "ne peut pas utiliser 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}

Essayez-le en ligne!

Encre de valeur
la source
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
Falko
la source
Parce que 3 est le plus grand, un nombre peut être le mod 4, vous pouvez remplacer le ==3par>2
FlipTack