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)

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.


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


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

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

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


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


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.


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

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  

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


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


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!


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

Porque 3 é o maior de um número pode ser mod 4, você poderia substituir o ==3com>2
— FlipTack
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.