Aggiunta in base -1 + i


64

Interi di Gauss sono numeri complessi della forma a+biin cui ae bsono entrambi interi. Nella base -1 + i, tutti i numeri interi gaussiani possono essere rappresentati in modo univoco usando le cifre 0e 1, senza la necessità di un simbolo per indicare il segno.

Ad esempio, 1100nella base -1 + i rappresenta il numero decimale 2, poiché

1*(-1+i)^3 + 1*(-1+i)^2 + 0*(-1+i)^1 + 0*(-1+i)^0
= (2+2i) + (-2i) + 0 + 0
= 2

L'input sarà due numeri interi gaussiani in base -1 + i rappresentati usando le cifre 01. Questo può assumere una delle seguenti forme:

  • Due stringhe di cifre separate,
  • Due numeri decimali consistenti nel 01rappresentare i numeri base -1 + i (ad es. 1100Per 2 nella base -1 + i),
  • Due numeri interi binari che rappresentano i numeri base -1 + i (ad es. Decimale 12o 0b1100per 2 nella base -1 + i)
  • Una singola stringa che separa stringhe a due cifre / numeri interi binari da un singolo separatore non alfanumerico (ad es. 1100 1100O 12,12per 2 + 2)

Emette la somma dei due numeri interi gaussiani, anch'essi in base -1 + i e rappresentati usando le cifre 01(in uno dei formati consentiti come input, non necessariamente la stessa scelta). L'output può contenere un numero finito di zeri iniziali.

La funzione o il programma deve terminare entro 2 secondi per gli input di massimo 30 cifre ciascuno.

Ulteriori chiarimenti

  • Si può presumere che l'ingresso non contenga zero iniziali estranei. Per il caso speciale di 0, è possibile scegliere una 0delle stringhe vuote come rappresentazione.

Casi test

0, 0 => 0                                      # 0 + 0 = 0
0, 1 => 1                                      # 0 + 1 = 1
1, 1 => 1100                                   # 1 + 1 = 2
1100, 1100 => 111010000                        # 2 + 2 = 4
1101, 1101 => 111011100                        # 3 + 3 = 6
110111001100, 1110011011100 => 0               # 42 + (-42) = 0
11, 111 => 0                                   # i + (-i) = 0
11, 110 => 11101                               # i + (-1-i) = -1
10101, 11011 => 10010                          # (-3-2i) + (-2+3i) = (-5+i)
1010100101, 111101 => 1110100000100            # (-19+2i) + (3-4i) = (-16-2i)

Casi di prova più lunghi:

11011011010110101110010001001, 111100010100101001001010010101 => 0
111111111111111111111111111111, 111111111111111111111111111111 => 100100100100100100100100100100
101101110111011101110111011101, 101101110111011101110111011101 => 11101001010001000100010001000100011100
100100010101001101010110101010, 100010011101001011111110101000 => 110000110010101100001100111100010

Nessun elenco di cifre?
CalculatorFeline

@CatsAreFluffy Nessuna lista di cifre, scusa.
Sp3000,

96
È possibile salvare un byte cambiando -1+iin i-1nel titolo.
mbomb007,

1
Ora abbiamo bisogno di una conversione al contrario. : P
Rɪᴋᴇʀ

3
Ci sono 1100 tipi di persone nel mondo. Quelli che comprendono il binario, quelli che non lo fanno, quelli che lo confondono con il ternario, quelli che lo confondono con la base 4, quelli che lo confondono con la base 5, quelli che lo confondono con la base -1 + i, quelli che lo confondono con base 6, quelli che lo confondono con la base 7, quelli che lo confondono con la base 8, quelli che lo confondono con la base 9 ...
wizzwizz4

Risposte:


42

Python 2, 98 97 91 84 byte

s=input();L=1
for _ in`s`*8:s+=1098*int(str(s).translate('0011'*64));L*=10
print s%L

Questo fa I / O in decimale. Gli interi devono essere separati dal carattere non alfanumerico +.

Grazie a @xnor per giocare a golf con 2 byte!

Provalo su Ideone .

Come funziona

In aritmetica in basi complesse , l'autore mostra come aggiungere e moltiplicare numeri complessi in basi della forma -n + i .

Per la base -1 + i , l'aggiunta viene eseguita in modo simile all'aggiunta binaria normale con carry, con due differenze:

  • Invece di portare 1 nella posizione più alta successiva, portiamo 110 nelle tre successive.

  • Le cifre di trasporto possono propagarsi indefinitamente. Tuttavia, senza zeri iniziali, la somma a + b ha al massimo otto cifre in più rispetto al massimo di un e b .

Procediamo come segue.

  1. In primo luogo, aggiungiamo un e b come se le loro cifre fossero cifre decimali.

    Per un = 10101 e b = 11011 , questo dà 21112 .

  2. Successivamente, formiamo un nuovo numero sostituendo le cifre maggiori di 1 con 1 , altre con 0 . 1

    Per la somma 21112 , questo dà 10001 .

  3. Per ogni cifra maggiore di 1 , dobbiamo sottrarre 2 da quella cifra e portare 110 alle successive tre posizioni più alte. Poiché 1098 = 10 * 110 - 2 , possiamo ottenere questo risultato moltiplicando il risultato dal passaggio 2 per 1098 , quindi aggiungendo quel prodotto alla somma. 2

    Per la somma 21112 , questo dà 21112 + 1098 * 10001 = 21112 + 10981098 = 11002210 .

  4. Ripetiamo i passaggi 2 e 3 per un totale di d * 8 volte, dove d è il numero di cifre di a + b . 3

    Per la somma iniziale 21112 , i risultati sono

                          11002210
                          12210010
                        1220010010
                      122000010010
                    12200000010010
                  1220000000010010
                122000000000010010
              12200000000000010010
            1220000000000000010010
          122000000000000000010010
        12200000000000000000010010
      1220000000000000000000010010
    122000000000000000000000010010
                                 .
                                 .
                                 .
    
  5. Prendiamo la somma finale modulo 10 d + 8 , scartando tutte tranne le ultime d + 8 cifre.

    Per la somma iniziale 21112 , il risultato finale è 10010 .


1 Questo si ottiene con translate . Ripetendo la stringa 0011 64 volte si allinea una ripetizione con la sequenza di caratteri ASCII 0123 , ottenendo la sostituzione desiderata.

2 Notare che le cifre di questa somma non possono superare 3 (valore iniziale 1 più due 1 's da carry).

3 Questo accade per d = 1 e d * 8> d + 8 altrimenti. Il codice può ripetere i passaggi (d + 1) * 8 volte, poiché s ha una L finale se s è un numero intero lungo .


7
Questa è magia profonda . Quale formato si input()aspetta? (Capisco 21112quando inserisco 10101, 11011.)
Tim Pederick il

1
Non importa; che stava eseguendo una versione tradotta (senza successo, a quanto pare) in Python 3. Funziona bene con Python 2 .
Tim Pederick,

9
...Come. Per favore. Spiegare.
Nic Hartley,

@QPaysTaxes Ho modificato la mia risposta.
Dennis,

@Dennis Ora potresti spiegare perché funziona? Ad esempio, perché d+8e no, diciamo d+9? Come????
Nic Hartley,

16

Pyth, 34 byte

_shM.u,%J/eMeN\12-+PMeNm.B6/J2k,kQ

Provalo online: Dimostrazione o Test Suite (richiede un po 'di tempo). Dovrebbe soddisfare la limitazione temporale anche se facilmente, poiché il compilatore online è piuttosto lento rispetto al normale compilatore (offline).

Spiegazione:

Il mio algoritmo è sostanzialmente un'implementazione di addizione con trasportare. Ma invece di trasportare 1, devo portare 110( 1100in base -1+iè uguale a 2in base -1+i). Funziona principalmente bene, ma puoi rimanere bloccato in un ciclo infinito di zeri di stampa. Ad esempio se stai aggiungendo 1con 11e attualmente hai il carry 110. Quindi praticamente aggiungo fino a quando non rimango bloccato in un ciclo e poi mi fermo. Penso che un ciclo che un ciclo stamperà sempre zeri e quindi questo dovrebbe andare bene.

_shM.u,%J/eMeN\12-+PMeNm.B6/J2k,kQ   implicit: Q = input list of strings
                               ,kQ   create the pair ["", Q]
    .u                               modify the pair N (^) until loop:
      ,                                replace N with a new pair containing:
            eN                           N[1] (the remaining summand)
          eM                             take the last digits of each summand
         /    \1                         count the ones
        J                                store the count in J
       %J       2                        J % 2 (this is the first element of the new pair)
                   PMeN                  remove the last digit of each summand
                  +    m   /J2           and add J / 2 new summand:
                        .B6                 with the value "110" (binary of 6)
                 -            k          remove empty summand
    .u                               returns all intermediate results
  hM                                 extract the digits
 s                                   sum them up to a long string
_                                    reverse

13

Python 2, 69 67 byte

f=lambda a,b:a*a+b*b^58and 2*f(a*b%2*6,f(a/2,b/2))|a+b&1if a else b

L'I / O viene eseguito con numeri interi di base 2.

-2 grazie @Dennis.


Lo prendo a*a+b*b^58==0quando ae bsono inverse? Come funziona?
xnor

@xnor No, a*a+b*b==58quando uno di questi è 3 e l'altro è 7.
feersum

1
Non è ovvio che (3,7)sia l'unica coppia che dà un ciclo e ha bisogno di un involucro speciale. Se è vero, allora devi solo fare il check-in (a,b)==(3,7)in quell'ordine, dal momento che si (7,3)ricorre a (3,7), e forse c'è un'espressione più breve per quello.
xnor

1
Ora questo è garantito per confondere chiunque non sappia (o dimentichi) che (a) ^è XOR, non esponenziale, o (b) XOR ha una precedenza inferiore rispetto a +.
Tim Pederick,

12

Retina , 100 byte

r+`(.*)(\d|(?!\4))( .*)(.?)
$2$4:$1$3
T` 0
+`1:11(1*:1*)11
:$1
^:*
:::
}`:(1*:1*:)11
1:1$1
(1)*:
$#1

Questo prende l'input separato da una virgola. L'output inizia sempre con tre zeri iniziali.

Provalo online!

Mi chiedo davvero se c'è una soluzione più breve per il primo stadio ...


2
No, no, il punteggio è perfetto così com'è;)
Conor O'Brien il

2
Bel punteggio di -2i!
Nic Hartley,

Wow. Non ho visto questa soluzione quando ho pubblicato la mia ... Molto più superiore della mia soluzione.
Leaky Nun,

@KennyLau Lo stavo solo guardando e pensando "hm, credo che avrei dovuto aggiungere una spiegazione ad un certo punto ..."
Martin Ender,

...- 2i? Questo è decimale ma il programma utilizza una base che non lo è.
user75200

12

Gelatina, 29 28 26 24 21 20 byte

DBḅ1100ḌµDL+8µ¡Dṣ2ṪḌ

Questo fa I / O in decimale. Gli interi devono essere separati dal carattere non alfanumerico +.

Provalo online! o verifica tutti i casi di test .

sfondo

In aritmetica in basi complesse , l'autore mostra come aggiungere e moltiplicare numeri complessi in basi della forma -n + i .

Per la base -1 + i , l'aggiunta viene eseguita in modo simile all'aggiunta binaria normale con carry, con due differenze:

  • Invece di portare 1 nella posizione più alta successiva, portiamo 110 nelle tre successive.

  • Le cifre di trasporto possono propagarsi indefinitamente. Tuttavia, senza zeri iniziali, la somma a + b ha al massimo otto cifre in più rispetto al massimo di un e b .

Procediamo come segue.

  1. In primo luogo, aggiungiamo un e b come se le loro cifre fossero cifre decimali.

    Per un = 10101 e b = 11011 , questo dà 21112 .

  2. Per ogni cifra maggiore di 1 , dobbiamo sottrarre 2 da quella cifra e portare 110 alle successive tre posizioni più alte. Possiamo raggiungere questo obiettivo convertendo ogni cifra decimale in binario, le matrici binarie risultanti dalla base 1100 in numero intero e interpretare l'elenco risultante di 0 , 1 , 1100 e 1101 come una base non canonica 10 numero. 1

    Per la somma 21112 , questo dà 21112 + 1098 * 10001 = 21112 + 10981098 = 11002210 .

  3. Ripetiamo i passaggi 2 per un totale di d + 8 volte, dove d è il numero di cifre di a + b .

    Per la somma iniziale 21112 , i risultati sono

                          11002210
                          12210010
                        1220010010
                      122000010010
                    12200000010010
                  1220000000010010
                122000000000010010
              12200000000000010010
            1220000000000000010010
          122000000000000000010010
        12200000000000000000010010
      1220000000000000000000010010
    122000000000000000000000010010
    
  4. Scartiamo tutte le cifre tranne d + 8 tranne il risultato finale. Questo si ottiene scartando tutto dopo gli ultimi 2 . 2

    Per la somma iniziale 21112 , il risultato finale è 10010 .

Come funziona

DBḅ1100ḌµDL+8µ¡Dṣ2ṪḌ  Main link. Argument: a + b (implicit sum)

        µ    µ¡       Execute the chain before the first µ n times, where n is
                      the result of executing the chain before the second µ.
         D            Convert a + b to base 10.
          L           Length; count the decimal digits.
           +8         Add 8 to the number of digits.
D                     Convert the initial/previous sum to base 10.
 B                    Convert each digit (0 - 3) to binary.
  ḅ1100               Convert each binary array from base 1100 to integer.
       Ḍ              Interpret the resulting list as a base 10 number.
               D      Convert the final sum to base 10.
                ṣ2    Split at occurrences of 2.
                  Ṫ   Select the last chunk.
                   Ḍ  Convert from base 10 to integer.

1 Nota che le cifre di questa somma non possono superare 3 (valore iniziale 1 più due 1 's da carry).

2 Funziona perché l'ultima cifra che verrà annullata non può essere un 3 .


6

Python 3, 289 byte

Questo esegue un'aggiunta digitale dal minimo al più significativo (in altre parole, lo stesso algoritmo che ti è stato insegnato nella scuola primaria). Le differenze sono che (a) è in binario, non decimale, quindi porti ogni volta che una cifra è 2 o più, e (b) 1 + 1 = 1100, no 10.

In realtà, è anche necessario notare che 11 + 111 = 0, altrimenti le somme che dovrebbero diventare zero non verranno mai interrotte.

from collections import*
def a(*s,p=0):
 r=defaultdict(int,{0:0})
 for S in s:
  n=0
  for d in S[::-1]:r[n]+=d=='1';n+=1
 while p<=max(r):
  while r[p]>1:
   r[p]-=2
   if r[p+1]>1<=r[p+2]:r[p+1]-=2;r[p+2]-=1
   else:r[p+2]+=1;r[p+3]+=1
  p+=1
 return str([*map(r.get,sorted(r))])[-2::-3]

Più golf è sicuramente possibile.


Quanto sei sicuro che il tuo "rilevatore zero" sia sufficiente?
Yakk,

4
@Yakk: Su una scala da uno a un giornale con revisione paritaria, forse potresti ancora fare un no-controesempio?
Tim Pederick,

2

Retina, 157 151 134 133 124 123 byte

1 byte spento grazie a Martin Büttner.

(.+),(.+)
$.1$*0$2,$.2$*0$1,
1
0x
+`(0x*)(,.*)0(x*),
$2,$1$3
{`,

(^|0x0xx0xx)
000
(0x*)(0x*)(0x*0)xx
$1x$2x$3
)`^0+
0
0x
1

Provalo online!

Converte in unario e quindi ripetere i seguenti rimpiazzi (mostrati qui in decimale):

122 -> 000
0002 -> 1100 (this can also be 0012 -> 1110 and 1112 -> 2210 or even 2222 -> 3320 or even 3333 -> 4431)

Fondamentalmente, quando è più grande di due: togli due, non aggiungere nulla nella cifra precedente, aggiungi uno alla cifra precedente, quindi aggiungi uno alla cifra precedente.

In pseudocodice:

if(a[n]>2):
    a[n] -= 2;
    a[n-2] += 1;
    a[n-3] += 1;

Implementazione unaria:

Ogni cifra (ad es. 3) Viene visualizzata come numero di xs (ad es. xxx) E quindi preceduta da 0.

Ad esempio, 1234sarebbe espresso come 0x0xx0xxx0xxxx.

Questo lascia 0invariato, come 101sarebbe espresso da 0x00x.

Poiché inizialmente e infine, esiste solo 0e 1, la conversione potrebbe essere facilmente eseguita da 1->0xe 0x->1.

Clicca qui per vedere ogni passaggio .


1

JavaScript (ES6), 146 126 byte

r=n=>n&&n%2-r(n>>=1)-i(n)
i=n=>n&&r(n>>=1)-i(n)
g=(x,y,b=(x^y)&1)=>x|y&&b+2*g(b-x+y>>1,b-x-y>>1)
(x,y)=>g(r(x)+r(y),i(x)+i(y))

g converte un intero gaussiano (parti reali e immaginarie) in base i-1 , mentre re iconverte una base i-1intero in un numero intero gaussiana (parte reale e immaginaria rispettivamente). Una volta che le conversioni sono a posto, devo solo fare l'aritmetica.

Modifica: salvato 20 byte calcolando le parti reali e immaginarie separatamente.


1

C ++ 416 byte, più #include <vector>\n#include <algorithm>\n(altri 40)

using I=int;using v=std::vector<I>;void r(v&x){v r{rbegin(x),rend(x)};x=r;}v a(v L,v R){r(L);r(R);L.resize(std::max(L.size(),R.size()));for(int&r:R)L[&r-R.data()]+=r;while(1){L.resize(L.size()+3);auto it=find(rbegin(L),rend(L),2);if(it==rend(L))break;I i=-1+it.base()-begin(L);i&&L[i+1]&&L[i-1]/2?L[i+1]=L[i]=L[i-1]=0:(++L[i+2],++L[i+3],L[i]=0);}L.erase( std::find(rbegin(L),rend(L),1).base(),end(L));r(L);return L;}

o, con più spazi bianchi:

using I=int;
using v=std::vector<I>;

void r(v&x){v r{rbegin(x),rend(x)};x=r;}
v a(v L,v R) {
  r(L);r(R);
  L.resize(std::max(L.size(),R.size()));
  for(int&r:R)
    L[&r-R.data()]+=r;
  while(1) {
    L.resize(L.size()+3);
    auto it=find(rbegin(L), rend(L), 2);
    if(it==rend(L)) break;
    I i=-1+it.base()-begin(L);
    i&&L[i+1]&&L[i-1]/2?
      L[i+1]=L[i]=L[i-1]=0
    :
      (++L[i+2],++L[i+3],L[i]=0);
  }
  L.erase( std::find(rbegin(L),rend(L),1).base(), end(L));
  r(L);
  return L;
}

A malapena golf. Prende l'input come vettore di ints e restituisce un vettore di ints.

Esempio dal vivo .

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.