is_gaussian_prime (z)?

23

Tarefa

Escreva uma função que aceite dois números inteiros a,bque representam o número inteiro gaussiano z = a+ib(número complexo). O programa deve retornar verdadeiro ou falso, dependendo de a+ibser um primo gaussiano ou não .

Definição:

a + bi é um primo gaussiano se, e somente se, atender a uma das seguintes condições:

  • ae bsão ambos diferentes de zero e a^2 + b^2é primo
  • aé zero, |b|é primo e|b| = 3 (mod 4)
  • bé zero, |a|é primo e|a| = 3 (mod 4)

Detalhes

Você deve escrever apenas uma função. Se o seu idioma não tiver funções, você pode assumir que os números inteiros estão armazenados em duas variáveis ​​e imprimir o resultado ou gravá-lo em um arquivo.

Você não pode usar funções internas do seu idioma como isprimeou prime_listou nthprimeou factor. O menor número de bytes vence. O programa deve trabalhar para a,bonde a^2+b^2está um número inteiro de 32 bits (assinado) e deve terminar em não mais do que 30 segundos.

Lista principal

Os pontos representam números primos no plano gaussiano ( x= real, y= eixo imaginário):

insira a descrição da imagem aqui

Alguns números primos maiores:

(9940, 43833)
(4190, 42741)
(9557, 41412)
(1437, 44090)
flawr
fonte
2
É permitido o uso de funções de fatoração ( factorno Bash mfe mFno CJam, ...)
Ah, não, eu esqueci que esses métodos de fatoração existiam, não, por favor, não =) E o limite de 32 bits se aplica a a ^ 2 + b ^ 2, não faria sentido de outra maneira. Obrigado por suas contribuições! Eu atualizei a pergunta.
flawr
2
Adicionei uma definição de números primos gaussianos ao post. Se você não gostar de como eu fiz isso, sinta-se à vontade para revertê-lo, mas eu recomendaria definitivamente incluir a definição em algum lugar.
Undergroundmonorail
Isso é bom, eu originalmente apenas não quis apontar diretamente para fora como para determinar a primality para que as pessoas para obter = criativas)
flawr
1 1073741857 não me parece um primo Gaussian porque 1 ^ 2 + 1073741857 ^ 2 é um número par ...
RosLuP

Respostas:

4

Haskell - 77/ 108 107 Caracteres

uso: nas duas soluções, digitar a% b retornará se a + bi é um primo gaussiano.

o mais baixo que consegui, mas sem criatividade ou desempenho (77 caracteres)

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

essa solução apenas fornece todos os números abaixo de n para verificar se é primo.

versão não destruída:

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)

a próxima solução possui um recurso extra - memorização. depois de verificar se algum número inteiro n é primo, não será necessário recalcular a "primeiridade" de todos os números menores ou iguais a n, pois ele será armazenado no computador.

(107 caracteres. Os comentários são para esclarecer)

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

versão não destruída:

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)

isso usa a peneira de Eratóstenes para calcular uma lista infinita de todos os números primos (chamados l para lista no código). (listas infinitas são um truque bem conhecido de haskell).

como é possível ter uma lista infinita? no início do programa, a lista não é avaliada e, em vez de armazenar os elementos da lista, o computador armazena a maneira de calculá-los. mas quando o programa acessa a lista, ele se avalia parcialmente até a solicitação. portanto, se o programa solicitar o quarto item da lista, o computador calculará todos os números primos até o quarto que ainda não foram avaliados, os armazenará e o restante permanecerá sem avaliação, armazenado como a maneira de computá-los uma vez necessário.

observe que tudo isso é dado livremente pela natureza preguiçosa da linguagem Haskell, nada disso é aparente no próprio código.

as duas versões do programa estão sobrecarregadas, para que possam manipular dados de tamanho arbitrário.

orgulhoso haskeller
fonte
Pelas minhas contas, sua primeira solução é realmente 77 caracteres: D
killmous
contei novas linhas, não deveria?
haskeller orgulhoso
Conto 74 caracteres regulares e 3 novas linhas
killmous
você está certo, parece que, por alguma razão, o bloco de notas ++ adiciona caracteres antes de novas linhas. obrigado!
haskeller orgulhoso
é por isso que uso sublime;) prazer em ajudar!
Killmous 7/08
9

C, 149 118 caracteres

Versão editada (118 caracteres):

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

Esta é uma função única:

  • G ( a , b ) retorna diferente de zero (verdadeiro) se a + bi for um primo gaussiano ou zero (falso) caso contrário.

Dobra o teste de primalidade inteira em uma expressão n/d/d|n<2oculta no cálculo do valor de retorno. Esse código também utiliza a*bcomo substituto a&&b(em outras palavras a!=0 && b!=0) e outros truques envolvendo precedência de operador e divisão de número inteiro. Por exemplo, n/d/dé uma maneira mais curta de dizer n/d/d>=1, que é uma maneira segura de estourar n>=d*dou dizerd*d<=n ou na sua essência d<=sqrt(n).


Versão original (149 caracteres):

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

Funções:

  • Q ( n ) retorna 0 (falso) se n for primo ou 1 (verdadeiro) se n for não primo. É uma função auxiliar para G ( a , b ).

  • G ( a , b ) retorna 1 (verdadeiro) se a + bi for um primo gaussiano ou 0 (falso) caso contrário.

Saída de amostra (aumentada em 200%) para | a |, | b | ≤ 128:

Amostra128

Todd Lehman
fonte
2
+1 para a imagem! Você poderia também fazer um sobre o mesmo tamanho apenas no primeiro quadrante (porque simetria), ele realmente parece ótimo aqui =)
flawr
Você pode salvar alguns caracteres substituindo d = 2; for (; n / d / d && n% d; d ++); com para (d = 2; n / d / d && n% d ++;);
Alchymist
@ Alchymist - Isso de fato salva caracteres, mas produz resultados incorretos. É importante que isso d++não aconteça como parte da condição; caso contrário, ela estraga a lógica a seguir. Além disso, mover o d=2interior do forloop na verdade aumenta a contagem de caracteres, em vez de diminuí-la, porque dainda precisa ser declarado como intanterior ao forloop. Estou esquecendo de algo?
Todd Lehman
Verdade demais. Perigos de olhar para isso longe de um ambiente de codificação e não de perto. O incremento precisa permanecer onde está e a inicialização apenas ajuda sua solução original. Existem economias óbvias se você declarar n & d fora da função, sem especificar int, e inicializá-las no loop for, mas presumo que você esteja tornando a função independente, o que é uma interpretação estrita dos requisitos.
Alchymist
11
O circuito de teste principal aqui é um golfe espetacular! No entanto, é possível obter ainda mais economia descartando os especificadores de tipo int para o tipo e argumentos de retorno, usando uma variável para | a | + | b | e otimizando a declaração de retorno: 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;}sai para apenas 97 caracteres.
precisa saber é
4

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

Pega uma matriz de dois números inteiros a be retorna o valor booleano da instrução a+bi is a Gaussian integer.

Edit: +11 bytes, porque eu não entendi a definição de um primo gaussiano. +1 byte de corrigir a resposta novamente. +1 byte de uma terceira correção de bug. -2 bytes devido ao uso de um trem em vez de um dfn. -4 bytes graças ao ngn devido ao uso de um protetor em condition: if_true ⋄ if_falsevez de if_true⊣⍣condition⊢if_false. -15 bytes graças ao ngn devido a encontrar uma maneira completamente diferente de escrever a condição if-else como um trem completo.

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

Experimente online!

Explicação

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

Haskell - 121 caracteres (novas linhas incluídas)

Aqui está uma solução Haskell relativamente simples que não usa nenhum módulo externo e tem o máximo de eficiência possível.

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

Invoque como ghci ./gprimes.hse, em seguida, você pode usá-lo no shell interativo. Nota: números negativos são complicados e devem ser colocados entre parênteses. Ou seja,

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

Python - 121 120 caracteres

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

pverifica se abs(x)é primo repetindo todos os números de 2 a abs(x)**.5(que é sqrt(abs(x))). Fá-lo cedendo x % spara cada um s. alldepois verifica se todos os valores obtidos são diferentes de zero e para de gerar valores quando encontrar um divisor de x. Em f, f(b,a)substitui o argumento b==0inspirado na resposta de Haskell de @killmous .


-1 char e correção de bug de @PeterTaylor

hlt
fonte
Eu contente poderia ajudar :)
killmous
Você poderia substituir s<abs(x)**.5com s*s<abs(x)uma poupança de 2. Embora realmente você deve estar verificando <=, por isso é provavelmente de buggy no presente.
Peter Taylor
@PeterTaylor Obrigado por apontar o erro ...
hlt
Chamando f(0,15)rendimentos TypeError: unsupported operand type(s) for &: 'bool' and 'generator'com meu intérprete. :(
Falko
f(0,15)Falsepara mim, tanto em 2.7.6 e 3.4.1 (no OS X). Em qual versão você está?
hlt
3

Python 2.7 , 341 301 253 bytes, otimizado para velocidade

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

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

Obrigado: 40 +48 - golfe inteiro para Jo King

Alexey Burdin
fonte
O flambda também é desnecessário, juntamente com a listchamada. 257 bytes sem esses, mais alguma remoção de espaço em branco. Isso talvez não seja tão eficiente mais embora
Jo rei
(15,0) agora é verdade em 257 bytes versão eo tempo de execução aumentou muito 5.5s, desculpe
Alexey Burdin
2

Perl - 110 107 105 caracteres

Espero ter seguido a definição vinculada corretamente ...

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

Explicação, porque alguém perguntou: Eu li os argumentos ( @_) e colocar seus valores absolutos em $a, $bnão porque a função não necessita de seu sinal. Cada um dos critérios requer o teste da primalidade de um número, mas esse número depende se$a ou $bnão zero, o que tentei expressar da maneira mais curta possível e colocar $n. Finalmente, verifico se $né primo contando quantos números entre 2 e ele próprio o dividimos sem deixar resto (essa é a grep...<2parte) e depois verifico se um dos números é zero, o outro é igual a 3 módulo 4. A função é O valor de retorno é por padrão o valor de sua última linha e essas condições retornam algum valor verdadeiro se todas as condições forem atendidas.

Tal
fonte
Não consigo fazê-lo funcionar com parâmetros negativos.
Killmous 7/08
11
@killmous você está certo, basta fixa-lo
Tal
você pode explicar o algoritmo?
proud haskeller
11
Agradável! A propósito, acho que você pode cortar alguns caracteres escrevendo em $a%4>2vez de $a%4==3.
Todd Lehman
2

golflua 147 141

A contagem acima negligencia as novas linhas que adicionei para ver as diferentes funções. Apesar da insistência em não fazê-lo, a força bruta resolve os primos nos casos.

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

Retorna 1 se verdadeiro e 0 se não.

Uma versão não-gasta de Lua,

-- 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
fonte
Você pode economizar 6 caracteres por apenas conectando tonumber(io.read())como um argumento para g, no fim, e mais 2, removendo as novas linhas
mniip
@ mniip: as novas linhas não foram contadas, apenas as adicionei para maior clareza (sem rolagem lateral). Atualizarei a leitura em g quando entrar em trabalho um pouco. Obrigado!
Kyle Kanos
Bem, ainda funciona em um período razoável de tempo para grandes números? Primeiramente, pensei em forçar brute na maneira de verificar todos os números inteiros gaussianos aonde |a| <= |z|if a | z(se adivide z).
flawr
@ flawr: Eu testei com a = 2147483644, b = 896234511 e obtive 0 em cerca de 0,002 s. Também testei com 2147483629 e 2147483587 (dois primos muito grandes) e obtive 0 em outros 0,002 s. Estou tentando encontrar um grande par de números, de modo que ^ 2 + b ^ 2 seja primo e garanta que eu tenha uma solução funcional para números tão grandes.
Kyle Kanos
@flawr: Testado com a = 4600 & b = 5603 (a ^ 2 + b ^ 2 = 2147393609 é primo & <2 ^ 32-1) e demorou os mesmos 0,002 segundos para retornar 1. Yay!
Kyle Kanos
1

APL (NARS), 99 caracteres, 198 bytes

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}

teste:

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

Encantos Rúnicos , 41 bytes

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

Experimente online!

Acabou sendo muito mais fácil do que eu pensava e não havia muito espaço para a golfificação. O programa original que bloqueei foi:

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

Eu brinquei com a tentativa de comparar as duas entradas ao mesmo tempo (que salvou todos os 1 byte), mas quando isso cai na seção "uma delas é zero", não havia uma boa maneira de descobrir qual item era diferente de zero para executar a última verificação, muito menos uma maneira de fazê-lo sem gastar pelo menos 1 byte (sem economia geral).

Draco18s não confia mais no SE
fonte
1

Mathematica, 149 caracteres

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

O código não usa nenhum recurso padrão de número primo do mathematica; em vez disso, conta o número de números inteiros na lista {n / 1, n / 2, ..., n / n}; se o número for 1 ou 2, então n é primo. Uma forma elaborada da função:

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

Gráfico de bônus de todos os Primes Gaussianos de -20 a 20:

Lote de primos gaussianos

raliano
fonte
1

Ruby -rprime , 65 60 80 bytes

Não percebeu a regra "não é possível usar 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}

Experimente online!

Value Ink
fonte
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
fonte
Porque 3 é o maior de um número pode ser mod 4, você poderia substituir o ==3com>2
FlipTack