Adição na base -1 + i

64

Inteiros gaussianos são números complexos da forma em a+bique ae bsão os dois inteiros. Na base -1 + i, todos os números inteiros gaussianos podem ser representados exclusivamente usando os dígitos 0e 1, sem a necessidade de um símbolo para indicar sinal.

Por exemplo, 1100na base -1 + i representa o número decimal 2, pois

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

A entrada será dois números inteiros gaussianos na base -1 + i representada usando os dígitos 01. Isso pode assumir uma das seguintes formas:

  • Duas cadeias de dígitos separadas,
  • Dois números inteiros decimais que consistem em 01representar os números da base -1 + i (por exemplo, 1100para 2 na base -1 + i),
  • Dois números inteiros binários representando os números da base -1 + i (por exemplo, decimal 12ou 0b1100para 2 na base -1 + i)
  • Uma única cadeia que separa duas cadeias de dígitos / números inteiros binários por um único separador não alfanumérico (por exemplo, 1100 1100ou 12,12para 2 + 2)

Emita a soma dos dois números inteiros gaussianos, também na base -1 + ie representados usando os dígitos 01(em um dos formatos permitidos como entrada, não necessariamente a mesma escolha). É permitido que a saída contenha um número finito de zeros à esquerda.

Sua função ou programa deve terminar dentro de 2 segundos para entradas de no máximo 30 dígitos cada.

Esclarecimentos adicionais

  • Você pode assumir que a entrada não contém zeros iniciais estranhos. Para o caso especial de 0, você pode escolher uma 0ou a sequência vazia como a representação.

Casos de teste

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)

Casos de teste mais longos:

11011011010110101110010001001, 111100010100101001001010010101 => 0
111111111111111111111111111111, 111111111111111111111111111111 => 100100100100100100100100100100
101101110111011101110111011101, 101101110111011101110111011101 => 11101001010001000100010001000100011100
100100010101001101010110101010, 100010011101001011111110101000 => 110000110010101100001100111100010
Sp3000
fonte
Nenhuma lista de dígitos?
CalculatorFeline
@CatsAreFluffy Nenhuma lista de dígitos, desculpe.
`` Sp3000
96
Você pode salvar um byte, alterando -1+ipara i-1no título.
mbomb007
11
Agora precisamos de uma conversão ao contrário. : P
Rɪᴋᴇʀ
3
Existem 1100 tipos de pessoas no mundo. Quem entende binário, quem não entende, quem o confunde com ternário, quem confunde com base 4, quem confunde com base 5, quem confunde com base -1 + i, quem confunde com base base 6, aqueles que confundi-lo com base 7, aqueles que confundi-lo com base 8, aqueles que confundi-lo com base 9 ...
wizzwizz4

Respostas:

42

Python 2, 98 97 91 84 bytes

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

Isso faz E / S em decimal. Os números inteiros devem ser separados pelo caractere não alfanumérico +.

Graças a @xnor por jogar fora 2 bytes!

Experimente em Ideone .

Como funciona

Em Aritmética em bases complexas , o autor mostra como adicionar e multiplicar números complexos em bases da forma -n + i .

Para a base -1 + i , a adição é feita de maneira semelhante à adição binária regular com carry, com duas diferenças:

  • Em vez de carregar 1 para a próxima posição mais alta, transportamos 110 para as próximas três.

  • Os dígitos de transporte podem se propagar indefinidamente. No entanto, sem zeros à esquerda, a soma a + b tem no máximo oito dígitos a mais do que o máximo de a e b .

Nós procedemos da seguinte maneira.

  1. Primeiro, adicionamos um e b como se seus dígitos eram dígitos decimais.

    Para a = 10101 e b = 11011 , o que dá 21112 .

  2. Em seguida, formamos um novo número substituindo os dígitos maiores que 1 por 1 , outros por 0 . 1

    Para a soma 21112 , isso fornece 10001 .

  3. Para cada dígito maior que 1 , temos que subtrair 2 desse dígito e transportar 110 para as próximas três posições mais altas. Como 1098 = 10 * 110-2 , podemos conseguir isso multiplicando o resultado da etapa 2 por 1098 e adicionando esse produto à soma. 2

    Para a soma 21112 , isso fornece 21112 + 1098 * 10001 = 21112 + 10981098 = 11002210 .

  4. Repetimos as etapas 2 e 3 um total de d * 8 vezes, em que d é o número de dígitos de a + b . 3

    Para a soma inicial 21112 , os resultados são

                          11002210
                          12210010
                        1220010010
                      122000010010
                    12200000010010
                  1220000000010010
                122000000000010010
              12200000000000010010
            1220000000000000010010
          122000000000000000010010
        12200000000000000000010010
      1220000000000000000000010010
    122000000000000000000000010010
                                 .
                                 .
                                 .
    
  5. Tomamos a soma final do módulo 10 d + 8 , descartando todos, exceto os últimos dígitos d + 8 .

    Para a soma inicial 21112 , o resultado final é 10010 .


1 Isso é conseguido com a tradução . Repetir a sequência 0011 64 vezes faz uma repetição alinhada com a sequência de caracteres ASCII 0123 , alcançando a substituição desejada.

2 Note-se que os dígitos desta soma não pode exceder 3 (valor inicial 1 , mais dois 1 's a partir carrega).

3 Isso funciona para d = 1 e d * 8> d + 8 caso contrário. O código pode repetir as etapas (d + 1) * 8 vezes, pois s tem um L à direita se s for um número inteiro longo .

Dennis
fonte
7
Isso é magia profunda . Que formato está input()esperando? (Eu recebo 21112quando eu entrada 10101, 11011.)
Tim Pederick
11
Deixa pra lá; que estava executando uma versão traduzida (sem êxito, ao que parece) para o Python 3. Funciona bem no Python 2 .
Tim Pederick
9
...Como. Por favor. Explicar.
22616 Nic Hartley
@QPaysTaxes Editei minha resposta.
Dennis
@Dennis Agora, você poderia explicar por que isso funciona? Por exemplo, por que d+8e não, digamos d+9,? Como????
Nic Hartley
16

Pitão, 34 bytes

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

Experimente on-line: Demonstration ou Test Suite (leva um bom tempo). Ele deve satisfazer a restrição de tempo com facilidade, pois o compilador online é bastante lento em comparação com o compilador normal (offline).

Explicação:

Meu algoritmo é basicamente uma implementação de adição com carry. Mas, em vez de carregar 1, eu tenho que carregar 110( 1100na base -1+ié o mesmo que 2na base -1+i). Isso funciona muito bem, mas você pode ficar preso em zeros de impressão de loop infinito. Por exemplo, se você está adicionando 1com 11e atualmente tem o carry 110. Então eu basicamente adiciono até ficar preso em um loop e depois parar. Eu acho que um loop que um loop sempre imprimirá zeros e, portanto, isso deve ficar bem.

_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
Jakube
fonte
13

Python 2, 69 67 bytes

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

A E / S é feita com números inteiros de base 2.

-2 obrigado @Dennis.

feersum
fonte
Eu tomo a*a+b*b^58==0quando ae bsão inversos? Como isso funciona?
xnor 23/03
@xnor Não, a*a+b*b==58quando um deles é 3 eo outro é 7.
feersum
11
Não é óbvio para mim que esse (3,7)é o único par que dá um ciclo e precisa de revestimento especial. Se for verdade, você só precisará fazer o check- (a,b)==(3,7)in nessa ordem, pois se (7,3)repete a (3,7), e talvez haja uma expressão mais curta para isso.
xnor 24/03
11
Agora, isso garante confundir quem não sabe (ou esquece) que (a) ^é XOR, não exponenciação, ou (b) XOR tem precedência menor que +.
Tim Pederick
12

Retina , 100 bytes

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

Isso leva a entrada separada por vírgula. A saída sempre começa com três zeros à esquerda.

Experimente online!

Eu realmente me pergunto se existe uma solução mais curta para a primeira etapa ...

Martin Ender
fonte
2
Não, não, a pontuação é perfeita como ela é;)
Conor O'Brien
2
Boa pontuação de -2i!
22616 Nic Hartley
Uau. Não vi essa solução quando publiquei a minha ... Muito mais superior que a minha solução.
Leaky Nun
@KennyLau eu estava apenas olhando para ele e pensando "hm, eu acho que deveria ter adicionado uma explicação em algum momento ..."
Martin Ender
...- 2i? Isso é decimal, mas o programa usa uma base que não.
user75200
12

Geléia, 29 28 26 24 21 20 bytes

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

Isso faz E / S em decimal. Os números inteiros devem ser separados pelo caractere não alfanumérico +.

Experimente online! ou verifique todos os casos de teste .

fundo

Em Aritmética em bases complexas , o autor mostra como adicionar e multiplicar números complexos em bases da forma -n + i .

Para a base -1 + i , a adição é feita de maneira semelhante à adição binária regular com carry, com duas diferenças:

  • Em vez de carregar 1 para a próxima posição mais alta, transportamos 110 para as próximas três.

  • Os dígitos de transporte podem se propagar indefinidamente. No entanto, sem zeros à esquerda, a soma a + b tem no máximo oito dígitos a mais do que o máximo de a e b .

Nós procedemos da seguinte maneira.

  1. Primeiro, adicionamos um e b como se seus dígitos eram dígitos decimais.

    Para a = 10101 e b = 11011 , o que dá 21112 .

  2. Para cada dígito maior que 1 , temos que subtrair 2 desse dígito e transportar 110 para as próximas três posições mais altas. Podemos conseguir isso convertendo cada dígito decimal em binário, as matrizes binárias resultantes da base 1100 em número inteiro e interpretando a lista resultante de 0 ', 1 ', 1100 'e 1101 ' como uma base não canônica 10 número. 1

    Para a soma 21112 , isso fornece 21112 + 1098 * 10001 = 21112 + 10981098 = 11002210 .

  3. Repetimos as etapas 2 um total de d + 8 vezes, em que d é o número de dígitos de a + b .

    Para a soma inicial 21112 , os resultados são

                          11002210
                          12210010
                        1220010010
                      122000010010
                    12200000010010
                  1220000000010010
                122000000000010010
              12200000000000010010
            1220000000000000010010
          122000000000000000010010
        12200000000000000000010010
      1220000000000000000000010010
    122000000000000000000000010010
    
  4. Nós descartamos todos, exceto os últimos d + 8 dígitos do resultado final. Isso é conseguido descartando tudo após os últimos 2 . 2

    Para a soma inicial 21112 , o resultado final é 10010 .

Como funciona

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 Note-se que os dígitos desta soma não pode exceder 3 (valor inicial 1 , mais dois 1 's a partir carrega).

2 Isso funciona porque o último dígito que será cancelado não pode ser um 3 .

Dennis
fonte
6

Python 3, 289 bytes

Isso realiza a adição digital a menos do dígito mais significativo (em outras palavras, exatamente o mesmo algoritmo que você aprendeu na escola primária). As diferenças são que (a) é binário, não decimal, então você carrega sempre que um dígito é 2 ou mais e (b) 1 + 1 = 1100não 10.

Na verdade, também é necessário observar que 11 + 111 = 0, caso contrário, as somas que devem se tornar zero nunca serão encerradas.

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]

Mais golfe é certamente possível.

Tim Pederick
fonte
Você tem certeza de que seu "detector zero" é suficiente?
Yakk 23/03/16
4
@Yakk: Em uma escala de um a um jornal revisado por pares, talvez você ainda não tenha um contra-exemplo?
Tim Pederick
2

Retina, 157 151 134 133 133 124 123 bytes

1 byte de desconto, graças 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

Experimente online!

Converte em unário e repita as seguintes substituições (mostradas aqui em decimal):

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

Basicamente, quando maiores que dois: retire dois, não adicione nada no dígito anterior, adicione um ao dígito anterior e adicione outro ao dígito anterior.

No pseudocódigo:

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

Implementação unária:

Cada dígito (por exemplo 3) é mostrado como o número de xs (por exemplo xxx) e, em seguida, prefixado com0 .

Por exemplo, 1234seria expresso como0x0xx0xxx0xxxx .

Isso deixa 0inalterado, como 101seria expresso por0x00x .

Como inicialmente e finalmente, existe apenas 0e 1, a conversão pode ser facilmente feita por 1->0xe0x->1 .

Clique aqui para ver todas as etapas .

Freira Furada
fonte
1

JavaScript (ES6), 146 126 bytes

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

gconverte um número inteiro de Gauss (partes reais e imaginárias) para a base i-1, ao mesmo tempo re ise converte uma basei-1 número inteiro em um número inteiro de Gauss (partes real e imaginária, respectivamente). Uma vez que as conversões estão no lugar, eu apenas tenho que fazer a aritmética.

Editar: salvou 20 bytes calculando as partes reais e imaginárias separadamente.

Neil
fonte
1

C ++ 416 bytes, mais #include <vector>\n#include <algorithm>\n(outros 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;}

ou, com mais espaço em branco:

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

Mal jogou golfe. Ele recebe entrada como um vetor de ints e retorna um vetor de ints.

Exemplo ao vivo .

Yakk
fonte