Gauss a Eisenstein


18

Dato un intero gaussiano a+bi dove a , b sono numeri interi e i=exp(πi/2) è l'unità immaginaria, restituisce il più vicino (wrt alla distanza euclidea) Eisenstein intero k+lω dove k , l sono numeri interi e ω=exp(2πi/3)=(1+i3)/2.

sfondo

È probabilmente abbastanza ovvio che ogni intero gaussiano può essere scritto in modo univoco come a+bi con a , b interi. Non è così ovvio, ma vero: qualsiasi numero intero di Eisenstein può essere scritto in modo univoco come k+lω con k , l numeri interi. Entrambi formano un modulo Z all'interno dei numeri complessi e sono entrambi interi ciclotomici p-th rispettivamente per p=2 o 3 . Si noti che 3+2i3+2ω

Fonte: commons.wikimedia.org

Dettagli

  • Nel caso in cui il numero complesso dato abbia due o tre punti più vicini, ognuno di questi può essere restituito.

  • Il numero complesso è indicato in coordinate rettangolari (base (1,i) ), ma diverso da quello in qualsiasi formato conveniente come (A,B)o A+Bio A+B*1jecc.

  • L'intero di Eisenstein deve essere restituito come coordinate della base (1,ω) ma diverso da quello in qualsiasi formato conveniente come (K,L)o K+Lωo K+L*1ωecc.

Esempi

Tutti i numeri interi reali dovrebbero ovviamente essere nuovamente mappati sui numeri interi reali.

  6,14 -> 14,16
  7,16 -> 16,18
-18,-2 ->-19,-2
 -2, 2 -> -1, 2
 -1, 3 -> 1, 4

Bello, non ricordo di aver visto una griglia esagonale da codegolf.stackexchange.com/q/70017/17602
Neil



Dovresti anche includere casi di test quando aeb hanno segni opposti.
SmileAndNod

@SmileAndNod Aggiunto uno. Ma si potrebbe anche usare la simmetria rispetto all'asse reale e sostituirla (1,w)con (-1,1+w). E ho anche rinominato questa sezione in Esempi per chiarire che non è sufficiente fornire i risultati giusti per questi casi.
Flawr

Risposte:


7

APL (Dyalog Extended) , 16 byte SBCS

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

Provalo online!

Un programma completo che prende yquindi xdallo standard input e stampa un vettore di 2 elementi di numeri interi.

Come funziona: la matematica

Prima di tutto, nota che qualsiasi intero gaussiano verrà posizionato sulla diagonale verticale di un diamante, con il punto Z posizionato su (x,3y)per alcuni numeri interix,y.

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

Nella figura, WZ¯=3 eWX¯=XY¯=YZ¯=XV¯=YV¯=13 . Quindi, data la posizione verticale di un punto, possiamo identificare il punto Eisenstein più vicino come segue:

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

Dato un punto gaussiano P , per prima cosa determiniamo a quale diamante P appartiene, misurato da quanti diamanti (indicato con h ) Z è lontano dall'asse x .

h=P.y÷3

Quindi le coordinate di Eisenstein di Z sono

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

WX¯,XY¯,YZ¯ Pw

w=P.y×3%3

w=0,1,2 correspond to YZ¯,XY¯,WX¯ respectively. Finally, the nearest Eisenstein point of P (which is one of Z, V, or X) can be calculated as:

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

Using the identities for h and w, we can further simplify to:

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

How it works: the code

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

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

ES7 can obviously trim 9 bytes. Explanation: k and l initially represent the floating-point solution to k+ωl=a+ib. However, the coordinates needed to be rounded to the nearest integer by Euclidean distance. I therefore take the floor of k and l, then perform some tests on the fractional parts to determine whether incrementing them would result in a nearer point to a+ib.


I guess your tests on the fractional parts are taking advantage of the facts that x is always .2887 or 0.577and y is always either .1547 or .577
SmileAndNod

@SmileAndNod 3 years ago? I really can't remember, but I don't think it's that complicated, I'm just working out which is the nearest corner of the diamond.
Neil

2

MATL, 39 38 35 bytes

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

Input format is 6 + 14*1j (space is optional). Output format is 14 16.

Try it online!

Explanation

The code first takes the input as a complex number. It then generates a big enough hexagonal grid in the complex plane, finds the point that is closest to the input, and returns its Eisenstein "coordinates".

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

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]

Try it online!

For input Gaussian integer (a,b), convert it into Eisenstein coordinates, floor and ceil both components to get four candidates for closest Eisenstein integer, find the one with minimal distance and return it.


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

Try it online!

This is somewhat inspired by the three-year old post from @Neil

The floor function returns the corner of the rhombus whose edges are the vectors 1 and ω. With respect to this rhombus, the Gaussian integer lies on the perpendicular bi-sector of either the top (if l is even) or bottom (if l is odd). This is important because it means that either the lower left corner or the upper right corner will be an acceptable solution. I compute k for the lower left corner, and do one test to see if the Gaussian integer lies above or below the diagonal separating the two corners; I add 1 to k when above the diagonal, and I do likewise for l.

Saved 10 bytes by using the "sign of the cross-product v x d of the diagonal d with the vector v joining the lower right corner and (a,b)" as the test for which side of the diagonal the point lies.


1

Burlesque, 24 bytes

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

Try it online!

Pretty sure this can be shorter. Input read as a 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

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.