Fattorizza un intero gaussiano


23

Un intero gaussiano è un numero complesso le cui parti reali e immaginarie sono numeri interi.

Gli interi gaussiani, come gli interi ordinari, possono essere rappresentati come un prodotto di numeri primi gaussiani, in un modo unico. La sfida qui è calcolare i costituenti primi di un dato intero gaussiano.

Input: un intero gaussiano, che non è uguale a 0 e non è un'unità (cioè 1, -1, i e -i non possono essere dati come input). Utilizzare qualsiasi formato sensibile, ad esempio:

  • 4-5i
  • -5 * j + 4
  • (4, -5)

Output: un elenco di numeri interi gaussiani, che sono primi (ovvero nessuno di essi può essere rappresentato come prodotto di due numeri interi gaussiani non unitari) e il cui prodotto è uguale al numero di input. Tutti i numeri nell'elenco di output devono essere non banali, ovvero non 1, -1, i o -i. È possibile utilizzare qualsiasi formato di output sensibile; non dovrebbe necessariamente essere lo stesso del formato di input.

Se l'elenco di output ha più di 1 elemento, sono possibili più output corretti. Ad esempio, per l'ingresso 9 l'uscita può essere [3, 3] o [-3, -3] o [3i, -3i] o [-3i, 3i].

Casi di test, (presi da questa tabella ; 2 righe per caso di test)

2
1+i, 1-i

3i
3i

256
1+i,1+i,1+i,1+i,1+i,1+i,1+i,1+i,1+i,1+i,1+i,1+i,1+i,1+i,1+i,1+i

7+9i
1+i,2−i,3+2i

27+15i
1+i,3,7−2i

6840+585i
-1-2i, 1+4i, 2+i, 3, 3, 6+i, 6+i

Le funzioni integrate per il factoring di numeri interi gaussiani non sono consentite. Tuttavia, è consentito il factoring di numeri interi ordinari mediante funzioni integrate.


Dovrebbe 3itornare come 3,i, o 3i?
Value Ink

3iè la risposta corretta perché inon è un numero primo. Ho aggiornato il test case per renderlo più chiaro.
Anatolyg,

-3-2j, 2-1j, -1-1j è una risposta corretta per la fattorizzazione di 7 + 9j?
mdahmoune,

4
Secondo Wolfram Alpha, 6840+585iha un elenco errato di fattori, in quanto 5non è un numero primo gaussiano. Invece, ritorna -1-2i, 1+4i, 2+i, 3, 3, 6+i, 6+i. Fonte
Value Ink,

1
Cordiali saluti, 256=(1+i)**16non (1+i)**8perché 256=2**8=(2i)**8e2i=(1+i)**2
Shieru Asakoto,

Risposte:


4

Gelatina , 61 55 byte

Ḟ,Ċ1ḍP
Ḟ,ĊḤp/-,1p`¤×€×1,ıFs2S€⁸÷ÇÐfỊÐḟ1;Ṫð,÷@\ḟ1
Ç€F$ÐL

Provalo online! (Intestazione e piè di pagina formatta l'output)

-6 byte grazie a @EricTheOutgolfer

Come funziona

Ḟ,Ċ1ḍP  - helper function: determines if a complex number is Gaussian
Ḟ,Ċ       - real, complex components
   1ḍ     - set each to if 1 divides them
     P    - all

Ḟ,ĊḤp/-,1p`¤×€×1,ıFs2S€⁸÷ÇÐfỊÐḟ1;Ṫð,÷@\ḟ1 - helper: outputs a factor pair of the input
Ḟ,ĊḤp/                   - creates a list of possible factors a+bi, a,b>=0
      -,1p`¤×€           - extend to the other three quadrants 
              ×1,ıFs2S€  - convert to  actual complex numbers 
⁸÷                       - get quotient with input complex number
  ÇÐf                    - keep only Gaussian numbers (using helper function)
     ỊÐḟ                 - remove units (i,-i,1,-1)
        1;               - append a 1 to deal with primes having no non-unit factors
          Ṫð,÷@\         - convert to a factor pair
                ḟ1       - remove 1s
Ç€F$ÐL
Ç€      - factor each number
   $    - and
  F     - flatten the list
    ÐL  - until factoring each number and flattening does not change the list


quando questo dice "mantieni solo gaussiano" significa "mantieni solo Primes"?
don luminoso

@donbright no, si riferisce a mantenere solo quei numeri complessi con componenti interi e complessi interi
fireflame241

@ fireflame241 oh vedo ora! grazie mille
don luminoso

5

Rubino , 258 256 249 246 + 8 = 264 257 254 byte

Usa la -rprimebandiera.

Accidenti, che casino.

Utilizza questo algoritmo da StackOverflow.

->c{m=->x,y{x-y*eval("%d+%di"%(x/y).rect)};a=c.abs2.prime_division.flat_map{|b,e|b%4<2?(1..e).map{k=(2..d=b).find{|n|n**(~-b/2)%b==b-1}**(~-b/4)%b+1i;d,k=k,m[d,k]while k!=0;c/=d=m[c,d]==0?d:d.conj;d}:(c/=b<3?(b=1+1i)**e:b**e/=2;[b]*e)};a[0]*=c;a}

Provalo online!


5

Python 2 , 250 239 223 215 byte

e,i,w=complex,int,abs
def f(*Z):
 if Z:
	z=Z[0];q=i(w(z));Q=4*q*q
	while Q>0:
 	 a=Q/q-q;b=Q%q-q;x=e(a,b)
 	 if w(x)>1:
		y=z/x
		if w(y)>1 and y==e(i(y.real),i(y.imag)):f(x,y);z=Q=0
 	 Q-=1
	if z:print z
	f(*Z[1:])

Provalo online!

  • -11 byte quando si utilizzano argomenti con funzioni multiple
  • -2² * ² byte quando si utilizza una variabile per analizzare le coppie (a,b)
  • -2³ byte quando si mescolano schede e spazi: grazie a ovs

Alcune spiegazioni ricompongono ricorsivamente un complesso in due complessi fino a quando non è possibile alcuna decomposizione ...


Bene, scade in TIO con input più grandi, ma è più breve della mia risposta di Ruby ... per ora . Inoltre, def f(Z,s=[])dovrebbe salvarti un personaggio
Value Ink,

@ValueInk sì, è più lento della tua soluzione ruby
mdahmoune,

2
Schema interessante con il rientro ...
Erik the Outgolfer,

@ValueInk Argomenti a più funzioni salva più byte :)
mdahmoune,

1
Puoi ridurre il conteggio dei byte mescolando tab e spazi
ovs

3

Ruggine - 212 byte

use num::complex::Complex as C;fn f(a:&mut Vec<C<i64>>){for _ in 0..2{for x in -999..0{for y in 1..999{for i in 0..a.len(){let b=C::new(x,y);if(a[i]%b).norm_sqr()==0&&(a[i]/b).norm_sqr()>1{a[i]/=b;a.push(b)}}}}}}

Non sono sicuro al 100% se questo funziona correttamente al 100%, ma sembra essere corretto per una vasta gamma di test. Questo non è più piccolo di Jelly, ma almeno è più piccolo delle lingue interpretate (finora). Sembra anche essere più veloce e può funzionare attraverso input di un miliardo di grandezza in meno di un secondo. Ad esempio 1234567890 + 3141592650i fattori come (-9487 + 7990i) (- 1 + -1i) (- 395 + 336i) (2 + -1i) (1 + 1i) (3 + 0i) (3 + 0i) (4+ 1i) (- 1 + 1i) (- 1 + 2i), (clicca qui per testare su wolfram alpha)

Questo è iniziato come la stessa idea del factoring ingenuo di numeri interi, passare attraverso ciascun numero sotto l'intero in questione, vedere se si divide, ripetere fino al termine. Quindi, ispirato da altre risposte, si è trasformato ... fattore più volte gli elementi in un vettore. Lo fa un buon numero di volte, ma non "fino a" nulla. Il numero di iterazioni è stato scelto per coprire una buona parte di input ragionevoli.

Utilizza ancora "(a mod b) == 0" per verificare se un numero intero ne divide un altro (per i gaussiani, usiamo il modulo gaussiano Rust incorporato e consideriamo "0" come norma == 0), tuttavia il controllo per 'norma ( a / b)! = 1 'impedisce di dividere "troppo", fondamentalmente permettendo al vettore risultante di essere riempito con solo numeri primi, ma non portando alcun elemento del vettore in unità (0-i, 0 + i, -1 + 0i, 1 + 0i) (che è vietato dalla domanda).

I limiti for-loop sono stati trovati attraverso l'esperimento. y va da 1 in su per prevenire il panico diviso per zero e x può andare da -999 a 0 grazie al mirroring dei gaussiani sui quadranti (penso?). Per quanto riguarda le limitazioni, la domanda originale non indicava un intervallo valido di input / output, quindi si presume una "dimensione di input ragionevole" ... (Modifica ... tuttavia non sono esattamente sicuro di come calcolare a quale numero questo sarà Comincio a "fallire", immagino ci siano numeri interi gaussiani che non sono divisibili per nulla al di sotto di 999 ma sono ancora sorprendentemente piccoli per me)

Prova la versione in qualche modo ungolfed su play.rust-lang.org


3

Perl 6 , 141 124 byte

Grazie a Jo King per -17 byte

sub f($_){{$!=0+|sqrt .abs²-$^a²;{($!=$_/my \w=$^b+$a*i)==$!.floor&&.abs>w.abs>1>return f w&$!}for -$!..$!}for ^.abs;.say}

Provalo online!


come funziona? il pavimento è un modulo personalizzato?
don luminoso

1
@donbright La floorparte sta controllando se $_/w(cioè il fattore attuale diviso per un numero) è un numero intero
Jo King

2

Pyth , 54 51 45 42 36 byte

 .W>H1cZ
h+.aDf!%cZT1>#1.jM^s_BM.aZ2

Provalo online!

Accetta input nella forma 1+2j: numeri puramente reali o immaginari possono omettere l'altro componente (ad esempio 9, 2j). L'output è un elenco separato da righe di numeri complessi, nella forma (1+2j), con numeri puramente immaginari che omettono la parte reale.

Questo utilizza una semplice divisione trail, generando tutti gli interi gaussiani con magnitudine maggiore di 1 e inferiore al valore corrente, più il valore stesso. Questi vengono filtrati per mantenere quelli che sono un fattore del valore e il più piccolo in ordine di grandezza viene scelto come fattore primo successivo. Questo viene generato e il valore viene diviso da esso per produrre il valore per la successiva iterazione.

Inoltre, Pyth batte Jelly 😲 (non mi aspetto che duri comunque)

 .W>H1cZ¶h+.aDf!%cZT1>#1.jM^s_BM.aZ2ZQ   Implicit: Q=eval(input())
                                         Newline replaced with ¶, trailing ZQ inferred
 .W                                  Q   While <condition>, execute <inner>, with starting value Q
   >H1                                   Condition function, input H
   >H1                                     Is magnitude of H > 1?
                                           This ensures loop continues until H is a unit, i.e. 1, -1, j, or -j)
      cZ¶h+.aDf!%cZT1>#1.jM^s_BM.aZ2Z    Inner function, input Z
                                .aZ        Take magnitude of Z

                             _BM           Pair each number in 0-indexed range with its negation
                            s              Flatten
                           ^       2       Cartesian product of the above with itself
                        .jM                Convert each pair to a complex number
                      #                    Filter the above to keep those element where...
                     > 1                   ... the magnitude is greater than 1 (removes units)
              f                            Filter the above, as T, to keep where:
                 cZT                         Divide Z by T
                %   1                        Mod real and imaginary parts by 1 separately
                                             If result of division is a gaussian integer, the mod will give (0+0j)
               !                             Logical NOT - maps (0+0j) to true, all else to false
                                           Result of filter are those gaussian integers which evenly divide Z
           .aD                             Sort the above by their magnitudes
          +                         Z      Append Z - if Z is ±1±1j, the filtered list will be empty
         h                                 Take first element, i.e. smallest factor
        ¶                                  Print with a newline
      cZ                                   Divide Z by that factor - this is new input for next iteration
                                         Output of the while loop is always 1 (or -1, j, or -j) - leading space suppesses output

questo è molto interessante ma sembra scadere il 6840 + 585j
don luminoso

@donbright Lo fa su TIO, poiché ha un limite di elaborazione di 60 secondi. Funzionerà con più tempo, quindi se lo stai eseguendo localmente dovrebbe funzionare senza problemi.
Ha cantato
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.