Gauss Faz Eisenstein

18

Dado um inteiro gaussiano a+bi onde a , b são inteiros e i=exp(πi/2) é a unidade imaginária, retorne o mais próximo (Wrt à distância euclidiana) inteiro Eisenstein k+lω onde k , l seja inteiros e ω=exp(2πi/3)=(1+i3)/2.

fundo

Provavelmente é bastante óbvio que todo número inteiro gaussiano pode ser exclusivamente escrito como a+bi com a , b inteiros. Não é tão óbvio, mas mesmo assim verdadeiro: qualquer número inteiro de Eisenstein pode ser exclusivamente escrito como k+lω com k , l números inteiros. Ambos formam um módulo Z dentro dos números complexos e são ambos os números inteiros ciclotômicos para p=2 ou 3 respectivamente. Observe que 3+2i3+2ω

Fonte: commons.wikimedia.org

Detalhes

  • Caso o número complexo fornecido tenha dois ou três pontos mais próximos, qualquer um deles poderá ser retornado.

  • O número complexo é dado em coordenadas retangulares (base (1,i) ), mas diferente daquele em qualquer formato conveniente como (A,B)ou A+Biou A+B*1jetc.

  • O inteiro Eisenstein deve ser retornado como coordenadas da base (1,ω) mas que não seja em qualquer formato conveniente como (K,L)ou K+Lωou K+L*1ωetc.

Exemplos

Todos os números inteiros reais obviamente devem ser mapeados para os números inteiros reais novamente.

  6,14 -> 14,16
  7,16 -> 16,18
-18,-2 ->-19,-2
 -2, 2 -> -1, 2
 -1, 3 -> 1, 4
flawr
fonte
Bom, eu não lembro de ter visto uma grade hexagonal desde codegolf.stackexchange.com/q/70017/17602
Neil
@ Neil Houve três outros desde então. ;)
Martin Ender
Você também deve incluir casos de teste quando aeb tiverem sinais opostos.
SmileAndNod 5/08/19
@SmileAndNod Adicionado um. Mas também se poderia usar a simetria em relação ao eixo real e substituir (1,w)por (-1,1+w). Também renomei esta seção para Exemplos para deixar claro que não é suficiente apenas fornecer os resultados corretos para esses casos.
flawr

Respostas:

7

APL (Dyalog Extended) , SBCS de 16 bytes

0+⌈3÷⍨1 2×⌊⎕×√3

Experimente online!

Um programa completo que leva y, em seguida, xa partir da entrada padrão e imprime um vector de 2-elemento de números inteiros.

Como funciona: a matemática

Primeiramente, observe que qualquer número inteiro gaussiano será colocado na diagonal vertical de um diamante, com o ponto Z colocado em (x,3y)para algum número inteirox,y.

      + W
     /|\
    / | \
   /  |  \
  /   + X \
 /    |    \
+-----|-----+V
 \    |    /
  \   + Y /
   \  |  /
    \ | /
     \|/
      + Z

Na figura, WZ¯=3 eWX¯=XY¯=YZ¯=XV¯=YV¯=13 . Portanto, dada a posição vertical de um ponto, podemos identificar o ponto Eisenstein mais próximo da seguinte maneira:

Given a point PWZ¯,{PWX¯the nearest point is WPXY¯the nearest point is VPYZ¯the nearest point is Z

Dado um ponto gaussiano P , primeiro determinamos a qual diamante P pertence, medido por quantos diamantes (denotados h ) Z estão afastados do eixo x .

h=P.y÷3

Então as coordenadas Eisenstein de Z são

Z.xE=P.x+h,Z.yE=2h

Agora, determinamos qual dos segmentos WX¯,XY¯,YZ¯ Ppertence. Para isso, podemos calcular o indicadorwseguinte maneira:

w=P.y×3%3

Então os casos w=0,1,2 correspondem a YZ¯,XY¯,WX¯ respectivamente. Finalmente, o ponto Eisenstein mais próximo de P (que é um de Z , V ou X ) pode ser calculado como:

PE.xE=P.x+h+w2,PE.yE=2h+w

Usando as identidades para h e w , podemos ainda simplificar a:

y=P.y×3,PE.xE=P.x+y÷3,PE.yE=2y÷3

Como funciona: o código

0+⌈3÷⍨1 2×⌊⎕×√3
           ⌊⎕×√3   Take the first input (P.y) and calculate y'
   ⌈3÷⍨1 2×       ⍝ Calculate [ceil(y'/3), ceil(2y'/3)]
⎕0+  ⍝ Take the second input(P.x) and calculate [P.x+ceil(y'/3), ceil(2y'/3)]
Bubbler
fonte
2

JavaScript (ES6), 112 bytes

(a,b,l=b/Math.pow(.75,.5),k=a+l/2,f=Math.floor,x=k-(k=f(k)),y=l-(l=f(l)),z=x+y>1)=>[k+(y+y+z>x+1),l+(x+x+z>y+1)]

O ES7 pode obviamente cortar 9 bytes. Explicação:k e linicialmente represente a solução de ponto flutuante para k+ωl=a+ib. No entanto, as coordenadas precisavam ser arredondadas para o número inteiro mais próximo pela distância euclidiana. Portanto, tomo a palavra ke l, em seguida, realizo alguns testes nas partes fracionárias para determinar se incrementá-las resultaria em um ponto mais próximo a+ib.

Neil
fonte
Eu acho que os testes sobre as partes fracionárias estão aproveitando os fatos que x é sempre 0,2887 ou 0.577and y é sempre quer 0,1547 ou 0,577
SmileAndNod
@SmileAndNod há 3 anos? Realmente não me lembro, mas não acho que seja tão complicado, só estou calculando qual é o canto mais próximo do diamante.
Neil
2

MATL , 39 38 35 bytes

t|Ekt_w&:2Z^tl2jYP3/*Zeh*!sbw6#YkY)

O formato de entrada é 6 + 14*1j(o espaço é opcional). O formato de saída é 14 16.

Experimente online!

Explicação

O código primeiro recebe a entrada como um número complexo. Em seguida, gera uma grade hexagonal grande o suficiente no plano complexo, encontra o ponto mais próximo da entrada e retorna suas "coordenadas" de Eisenstein.

t         % Take input implicitly. This is the Gauss number, say A. Duplicate
|Ek       % Absolute value times two, rounded down
t_        % Duplicate and negate
w&:       % Range. This is one axis of Eisenstein coordinates. This will generate
          % the hexagonal grid big enough
2Z^       % Cartesian power with exponent 2. This gives 2-col 2D array, say B
t         % Duplicate
l         % Push 1
2jYP3/*   % Push 2*j*pi/3
Ze        % Exponential
h         % Concatenate. Gives [1, exp(2*j*pi/3)]
*         % Multiply by B, with broadcast.
!s        % Sum of each row. This is the hexagonal grid as a flattened array, say C
bw        % Bubble up, swap. Stack contains now, bottom to top: B, A, C
6#Yk      % Index of number in C that is closest to A
Y)        % Use as row index into B. Implicitly display
Luis Mendo
fonte
2

Haskell , 128 bytes

i=fromIntegral;r=[floor,ceiling];a!k=(i a-k)**2;c(a,b)|l<-2*i b/sqrt 3,k<-i a+l/2=snd$minimum[(x k!k+y l!l,(x k,y l))|x<-r,y<-r]

Experimente online!

Para o número inteiro gaussiano de entrada (a, b), converta-o em coordenadas de Eisenstein, aplique piso e teto de ambos os componentes para obter quatro candidatos ao número inteiro Eisenstein mais próximo, encontre o que tiver distância mínima e retorne-o.

Sacchan
fonte
1

Tcl , 124 116 106 bytes

{{a b f\ int(floor(2*$b/3**.5)) {l "[expr $f+(1-$f%2<($b-$f)*3**.5)]"}} {subst [expr $l+$a-($f+1)/2]\ $l}}

Experimente online!

Isso é um pouco inspirado no post de três anos do @Neil

ω . Com relação a esse losango, o número inteiro gaussiano está no bi-setor perpendicular do topo (se l for par) ou do fundo (se l for ímpar). Isso é importante porque significa que o canto inferior esquerdo ou o canto superior direito será uma solução aceitável. Calculo k para o canto inferior esquerdo e faço um teste para verificar se o número inteiro gaussiano está acima ou abaixo da diagonal que separa os dois cantos; Eu adiciono 1 a k quando estiver acima da diagonal e o mesmo para l.

Economizou 10 bytes usando o "sinal do produto cruzado vxd da diagonal d com o vetor v unindo o canto inferior direito e (a, b)" como o teste para qual lado da diagonal o ponto está.

SmileAndNod
fonte
1

Burlesco , 24 bytes

pe@3r@2././J2./x/.+CL)R_

Experimente online!

Certamente isso pode ser mais curto. Entrada lida comoa b

pe      # Parse input to two ints
@3r@2./ # sqrt(3)/2
./      # Divide b by sqrt(3)/2
J2./    # Duplicate and divide by 2
x/.+    # swap stack around and add to a
CL      # Collect the stack to a list
)R_     # Round to ints
DeathIncarnate
fonte