Números binários complexos

36

Vamos criar um mapeamento subjetivo simples de números inteiros positivos para números gaussianos , que são números complexos em que as partes reais e imaginárias são números inteiros.

Dado um número inteiro positivo, por exemplo 4538, expresse-o em binário sem líderes 0:

4538 base 10 = 1000110111010 base 2

Remova qualquer trilha 0:

100011011101

Substitua qualquer execução de uma ou mais 0por uma única +:

1+11+111+1

Substitua todos 1por i:

i+ii+iii+i

Avalie a expressão complexa resultante e produza o número inteiro gaussiano simplificado:

i+ii+iii+i = i+i*i+i*i*i+i = 2i+i^2+i^3 = 2i+(-1)+(-i) = -1+i

A saída pode ser expressa de uma maneira matemática tradicional ou fornecida como dois números inteiros separados para as partes real e complexa. Por 4538exemplo, qualquer um deles seria bom:

-1+i
i-1
-1+1i
(-1, 1)
-1 1
-1\n1

Para entradas como 29, saídas de Mathy formatado como 0, 0iou 0+0isão todos muito bem.

Usar j(ou qualquer outra coisa) em vez de ié bom se isso for mais natural para o seu idioma.

O código mais curto em bytes vence.

Passatempos de Calvin
fonte
Desde o título pensei que o desafio seria de cerca de números complexos em binário, por exemplo 4+2j-> 100+10j...
Erik o Outgolfer

Respostas:

22

MATL , 7 bytes

BJ*Y'^s

Experimente online!

Como funciona

Considere entrada, 4538por exemplo.

B     % Implicit input. Convert to binary
      % STACK: [1 0 0 0 1 1 0 1 1 1 0 1 0]
J*    % Multiply by 1i
      % STACK: [1i 0 0 0 1i 1i 0 1i 1i 1i 0 1i 0]
Y'    % Run-length encoding
      % STACK: [1i 0 1i 0 1i 0 1i 0], [1 3 2 1 3 1 1 1]
^     % Power, element-wise
      % STACK: [1i 0 -1 0 -1i 0 1i 0]
s     % Sum of array. Implicit display
      % STACK: -1+1i
Luis Mendo
fonte
2
7 bytes em MATL, e o melhor que posso obter é 58 em MATLAB ... Você criou uma pequena linguagem agradável lá! =)
Stewie Griffin
1
O @StewieGriffin é facilmente o melhor do programa quando se trata de gráficos ou plotagens, talvez também para aritmética matricial também pelas respostas impressionantes que eu o vi postar.
Magic Octopus Urn
13

Geléia , 8 bytes

BŒgaıP€S

Experimente online!

Como funciona

BŒgaıP€S  Main link. Argument: n (integer)

B         Convert to binary.
          If n = 4538, this yields [1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0].
 Œg       Group equal elements.
          This yields [[1], [0, 0, 0], [1, 1], [0], [1, 1, 1], [0], [1], [0]].
   aı     Logical AND with the imaginary unit.
          This yields [[ı], [0, 0, 0], [ı, ı], [0], [ı, ı, ı], [0], [ı], [0]].
     P€   Product each.
          This yields [ı, 0, -1, 0, -ı, 0, ı, 0].
       S  Sum.
          This yields -1+ı.
Dennis
fonte
10

Python 2, 53 bytes

f=lambda n,k=0:(n and f(n/2,n%2*(k or 1)*1j))+~n%2*k

Estou tentando golfe isso e parece golfable, mas estou sem idéias atm ...

Sp3000
fonte
1
Que (k or 1)não parece ideal, mas a única coisa que posso pensar é (k+0**k)...
ETHproductions
@ETHproductions Meus pensamentos exatamente, mas, infelizmente, 0**knão funciona para complexo k...
SP3000
6

Mathematica, 44 38 bytes

Tr[1##&@@@Split[I*#~IntegerDigits~2]]&

Explicação

#~IntegerDigits~2

Converta a entrada na base 2. ( 4538torna-se {1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0})

I*

Multiplique por I( {1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0}se torna {I, 0, 0, 0, I, I, 0, I, I, I, 0, I, 0})

Split

Dividir por execuções ( {I, 0, 0, 0, I, I, 0, I, I, I, 0, I, 0}torna-se {{I}, {0, 0, 0}, {I, I}, {0}, {I, I, I}, {0}, {I}, {0}})

1##&@@@ ...

Encontre o produto no nível 2. ( {{I}, {0, 0, 0}, {I, I}, {0}, {I, I, I}, {0}, {I}, {0}}torna-se {I, 0, -1, 0, -I, 0, I, 0})

Tr

Soma o resultado. ( {I, 0, -1, 0, -I, 0, I, 0}torna-se -1 + I)

JungHwan Min
fonte
menos 1 byte:Tr[Times@@@(I*Split@RealDigits[#,2][[1]])]&
martin
1
@martin Bem, eu usei sua ideia de multiplicar Iprimeiro, mas IntegerDigitsacabei sendo mais curta.
JungHwan Min
sim - muito melhor :)
martin
5

Python 2 , 77 76 71 bytes

p=r=0
for n in bin(input()*2):t=n=='1';r-=p*~-t;p=p*t*1jor t*1j
print r

Graças a @ZacharyT por jogar fora um byte!

Experimente online!

Dennis
fonte
5

JavaScript (ES6), 67 64 bytes

f=(n,q=0,a=[0,0])=>q|n?f(n/2,n&1?q+1:q&&0*(a[q&1]+=1-(q&2)),a):a
<input oninput="O.innerHTML=f(this.value)" type="number" step=1 min=0 value="4538">
<pre id=O></pre>

Saídas como uma matriz de 2 elementos.

Explicação

Como o JavaScript não possui números imaginários, precisamos acompanhar as partes reais e imaginárias em variáveis ​​separadas. A maneira mais fácil de fazer isso é em uma única matriz, com a parte real primeiro. i é representado como [0,1] , i 2 (ou -1 ) como [-1,0] , i 3 (ou -i ) como [0, -1] e i 4 (ou 1 ) como [1 , 0] .

Primeiro, dividimos repetidamente o número por 2, coletando cada corrida de uma na sua representação binária. Cada série de n corresponde a i n . Isso corresponde à adição de 1 - (n & 2) ao item no índice n & 1 na matriz de dois itens. Então é isso que fazemos.

Provavelmente devo acrescentar mais explicações, mas não consigo pensar no que mais precisa ser explicado. Sinta-se livre para comentar com qualquer dúvida que possa ter.

ETHproductions
fonte
5

Python, 199 129 124 116 94 90 71 63 61 bytes

print sum(1j**len(s)for s in bin(input())[2:].split('0')if s)

A entrada é apenas o número em si.
A saída está no formato (a+bj), onde jestá a unidade imaginária. 0jserá produzido em vez de(0+0j)

Primeiro converta para binário. Trunque a '0b'desativação. Mate os zeros à direita. Divida usando um bloco de zero (s) como delimitador. Mapeie cada bloco para 1j ** len. Então, pegue a soma da coisa toda.

-70 bytes por não converter em vantagens. Regex de
-5 bytes é mais curto.
-8 bytes , livrando-se das duas variáveis ​​desnecessárias que estavam sendo chamadas apenas uma vez.
-22 bytes usando números complexos em vez da minha coisa estranha. Obrigado à resposta do @Dennis 'por me informar sobre números complexos!
-4 bytes ao perceber que essa mapé apenas uma maneira sofisticada de compreender a lista, exceto por mais tempo.
-19 bytes , alternando para um método ligeiramente arcano de evitar erros j ** 0e regex. Inspirado pelo comentário de @ Griffin. Obrigado! :)
-8 bytes movendo a ifpeça até o fim.
-2 bytes Agradecemos ao @Griffin por salvar 2 bytes removendo os colchetes para torná-lo uma expressão de gerador!

HyperNeutrino
fonte
Eu tenho algo bastante semelhante de modo a não postar resposta em separado, pouco menor quesum(1j**x.count('1')for x in bin(input()).split('0')if x)
Griffin
@Griffin Nice. Eu acho que é diferente o suficiente para que você possa postar uma resposta separada, pois usa um método diferente de contar os 1blocos e não usa regex como o meu. Além disso, não quero roubar o código de você, pois é muito melhor que a minha versão. :)
HyperNeutrino
@ Griffin Encontrei outra solução com o mesmo comprimento que a sua solução, exceto que, em vez de contar 1s em vez de comprimento, ela tira a 0xparte da frente primeiro. Obrigado pela idéia de mover o ifpara o fim; Eu nunca saberia que funciona de outra maneira!
HyperNeutrino
você não precisa da compreensão da lista. Remova os colchetes para torná-lo uma expressão de gerador
Griffin
@Griffin Oh. Ok, obrigada! Vou lembrar que para o futuro golfe
HyperNeutrino 6/16
4

MATLAB, 58 bytes

@(x)eval([strrep(strrep(dec2bin(x),48,43),49,'i*1'),'.0'])

dec2bin(x) % converts the decimal value to a binary string of 1s and 0s.
strrep(dec2bin(x),48,43) % Substitutes ASCII character 48 with 43 (0s become +)
strrep(___,49,'i*1')     % Substitutes ASCII character 49 with 'i*1'
                         % 1s become 'i*1' (this is the gem)
eval([___,'.0']          % Appends .0 in the end and evaluates the expression.   

Vamos usar 285para ilustrar o processo:

temp1 = dec2bin(285)
      = 100011101

temp2 = strrep(temp1,48,43)
      = 1+++111+1

Felizmente 1+++1se comporta exatamente como 1+1no MATLAB, de modo que os avalia acima para: 1+111+1.

temp3 = strrep(temp2,49,'i*1')
      = i*1+++i*1i*1i*1+i*1

Agora, essa strrepchamada é a verdadeira jóia! Através da inserção i*1para 1nós conseguir algo muito bom. Se houver apenas um 1, simplesmente obtemos i*1qual é i. Se houver mais de uma, em seguida, i*1se repete e concatenadas em uma seqüência: i*1i*1i*1i*1. Desde i==1iem MATLAB e 1i*1==iisso simplesmente é: i*i*i*i.

temp4 = [temp3,'.0']
      = i*1+++i*1i*1i*1+i*1.0

Anexar .0parece desnecessário aqui, mas é necessário se o último caractere de temp3for a +. Não podemos acrescentar apenas um zero, pois isso daria i*10no caso acima e, portanto, o resultado errado.

E finalmente:

eval(temp4)
0.0000 + 1.0000i

Isso não funciona no Octave por vários motivos. strrepnão pode aceitar valores ASCII como entrada, ele precisa dos caracteres reais (em '0'vez de 48). Além disso, +++não avalia apenas +no Octave, pois isso quebraria os atalhos de incremento / decremento x++e x--.

Stewie Griffin
fonte
1
Sempre +1 para usar eval:-P Você não pode usar em 1ivez de 1*i?
Luis Mendo
1
Oh, você está usando diferente. Muito esperto!
Luis Mendo
Obrigado :-) Devo admitir, fiquei bastante satisfeito com o i*1 parte ...
Stewie Griffin
2

Mathematica, 84 bytes

ToExpression[#~IntegerString~2~StringTrim~"0"~StringReplace~{"0"..->"+","1"->"I "}]&

Função anônima. Pega um número como entrada e retorna um número complexo como saída.

LegionMammal978
fonte
6
Uau, estou surpreso que o Mathematica não tenha um built-in para isso!
HyperNeutrino 04/04/19
2

Mathematica, 75 bytes

ToExpression[#~IntegerString~2~StringReplace~{"1"->"I ","0"..->"+"}<>"-0"]&

Independentemente, surgiu quase a mesma solução que o LegionMammal978 postou 23 minutos atrás! Substituir 1por I (que é o símbolo interno do Mathematica para a raiz quadrada de -1) funciona porque os espaços são tratados como multiplicação de expressões vizinhas. O lugar que salvei na outra solução, ou seja, evitando a necessidade StringTrim, é sempre acrescentando -0: se o número binário termina 1, então essa expressão termina no ...I-0que não afeta seu valor; enquanto se o número binário termina em '0', essa expressão termina na ...+-0qual é analisada como "adicione 0 negativo" e, assim, se livra do sinal de adição à direita.

Greg Martin
fonte
2

Matlab, 99 bytes

function c=z(b)
c=0;b=strsplit(dec2bin(b),'0');for j=1:numel(b)-isempty(b{end});c=c+i^nnz(b{j});end

Casos de teste:

z(656) = 3i
z(172) = -1 + 2i
z(707) = -2 + i
z(32)  = i
z(277) = 4i
Owen Morgan
fonte
2

Haskell, 102 91 89 87 bytes

0%a=a
n%c@[a,b]|odd n=div n 2%[-b,a]|d<-div n 2=zipWith(+)c$d%[mod d 2,0]
(%[0,0]).(*2)

Divide repetidamente por dois e verifica o bit. Mantém um acumulador de i^(number of odds)onde a+b*ié codificado como [a,b]e *ié [a,b]↦[-b,a](rotação de 90 graus). A inicial (*2)é evitar uma pesquisa para o primeiro bit.

Uso (obrigado a @OwenMorgan pelos exemplos):

(%[0,0]).(*2)<$>[656,172,707,32,277]
[[0,3],[-1,2],[-2,1],[0,1],[0,4]]
Angs
fonte
1

Java, 172 bytes

l->{int i=0,j=i;for(String x:l.toString(2).split("0")){int a=x.length();j+=a&1>0?(a&3>2?(a-3)/-4+1:(a-3)/4+1):0;i+=a&1<1?(a&3>1?(a-3)/4+1:(a-3)/-4+1):0;}return i+"|"j+"i";}
Roman Gräf
fonte
1

Clojure, 183 bytes

#(loop[x(clojure.string/split(Integer/toString % 2)#"0+")y[0 0]a 0](if(= a(count x))y(recur x(let[z([[1 0][0 1][-1 0][0 -1]](mod(count(x a))4))][(+(y 0)(z 0))(+(y 1)(z 1))])(inc a))))

Posso fazer isso?

Use a função da seguinte maneira:

(#(...) {num}) -> (Wrap the # function in brackets first!)
clismique
fonte
1

Na verdade , 35 bytes

├'0' aÆô' @s"j+"j'jo`"1j*1"'1τ(Æ`Y≡

Experimente online!

Explicação:

├'0' aÆô' @s"j+"j'jo`"1j*1"'1τ(Æ`Y≡
├                                    binary representation of input
 '0' aÆ                              replace 0s with spaces
       ô                             trim leading and trailing spaces
        ' @s                         split on spaces
            "j+"j                    join with "j+"
                 'jo                 append "j"
                    `"1j*1"'1τ(Æ`Y   do until the string stops changing (fixed-point combinator):
                     "1j*1"'1τ(Æ       replace "11" with "1j*1"
                                  ≡  evaluate the resulting string to simplify it

Código Python 3 aproximadamente equivalente:

a='j+'.join(bin(eval(input()))[2:].replace('0',' ').strip().split())+'j'
b=0
while a!=b:b,a=a,a.replace("11","1j*1")
print(eval(a))

Experimente online!

Mego
fonte
Dividir em '0's com '0@se usar ``░para aparar qualquer sequência vazia à direita deve economizar quatro bytes.
Sherlock9
1

Gelatina , 10 bytes

Isso não é melhor do que a resposta de Dennis Jelly, mas eu queria tentar de qualquer maneira uma resposta de Jelly. Sugestões de golfe são bem-vindas! Experimente online!

BŒrm2Ṫ€ı*S

Ungolfing

BŒrm2Ṫ€ı*S   Main link. Argument: n (integer)

B            Convert n to binary.
 Œr          Run-length encode the binary list.
   m2        Every 2nd element of the run_length encoding, getting only the runs of 1s.
     Ṫ€      Tail each, getting only the lengths of the runs.
       ı*    The imaginary unit raised to the power of each run (as * is vectorized).
         S   Sum it all into one complex number.
Sherlock9
fonte
No link acima A entrada 1 retorna 1j a entrada 2 retorna 1j .... Está certo?
RosLuP
@RosLuP Sim, está certo? Como removemos os zeros à direita, 1 => 1 => 1jé equivalente a 2 => 10 => 1 => 1j.
Sherlock9
1

Na verdade , 15 bytes

Sugestões de golfe são bem-vindas! Experimente online!

├'0@s``░`lïⁿ`MΣ

Ungolfing:

         Implicit input n.
├        Convert n to binary.
'0@s     Split by '0's.
``░      Filter out non-truthy values.
`...`M   Map over the filtered result, a list of runs of '1's.
  l        Yield the length of the run of '1's.
  ïⁿ       Yield the imaginary unit to the power of that length.
Σ        Sum all of this into one complex number.
Sherlock9
fonte
0

Axioma, 140, 131, 118 108 bytes

b(x)==(s:=0;repeat(x=0=>break;r:=x rem 2;repeat(x rem 2=1=>(r:=r*%i;x:=x quo 2);break);s:=s+r;x:=x quo 2);s)

% i é o cliente imaginário.

sb(x:NNI):Complex INT==
  r:Complex INT;s:Complex INT:=0
  repeat
    x=0=>break
    r:=x rem 2
    repeat
       x rem 2=1=>(r:=r*%i;x:=x quo 2)
       break
    s:=s+r
    x:=x quo 2
  s

resultados

(3) -> b 4538
   The type of the local variable r has changed in the computation.
   We will attempt to interpret the code.
   (3)  - 1 + %i
                                                    Type: Complex Integer
(4) -> b 29
   (4)  0
                                                    Type: Complex Integer
(5) -> sb 299898979798233333333333333339188888888888888888222
   Compiling function sb with type NonNegativeInteger -> Complex Integer
   (5)  - 7 + 12%i
                                                    Type: Complex Integer
(6) -> b 299898979798233333333333333339188888888888888888222
   (6)  - 7 + 12%i
                                                    Type: Complex Integer
RosLuP
fonte
0

Perl 6 ,  40  46 bytes

Eu vim com isso rapidamente

*.base(2).comb(/1+/).map(i***.chars).sum

Infelizmente, atualmente é impreciso na implementação do Rakudo no MoarVM .
say i ** 3; # -1.83697019872103e-16-1i

Então eu tive que fazer a próxima melhor coisa:

*.base(2).comb(/1+/).map({[*] i xx.chars}).sum

Expandido:

*\             # Whatever lambda
.base(2)       # convert to a Str representation in base 2
.comb(/ 1+ /)  # get a list of substrings of one or more 「1」s
.map({         # for each of those

  [*]            # reduce using 「&infix:<**>」
    i xx .chars    # 「i」 list repeated by the count of the characters matched

}).sum          # sum it all up

Teste:

.say for (4538, 29).map:

    *.base(2).comb(/1+/).map({[*] i xx.chars}).sum

# -1+1i
# 0+0i
Brad Gilbert b2gills
fonte
Relatório de bug arquivado
Brad Gilbert b2gills
0

PHP, 87 bytes

for($n=$argv[1];$n|$i;$n>>=1)$n&1?$i++:($i?$i=0*${$i&1}+=1-($i&2):0);echo"(${0},${1})";

Quase o mesmo que a solução ETHproductions; apenas iterativo em vez de recursivo.
Pega entrada da linha de comando, define variáveis ${0}e ${1}.

Titus
fonte
0

TI-Basic (TI-84 Plus CE), 70 bytes

Prompt X
0→S
0→N
While X
If remainder(X,2
Then
N+1→N
int(X/2→X
Else
S+i^Nnot(not(N→S
X/2→X
0→N
End
End
S+i^Nnot(not(N

Não há um builtin para converter em uma string binária (nem existe para analisar uma string); portanto, este programa divide-se manualmente por 2, incrementando N cada vez que vê 1 e adicionando i ^ N a S (N> 0) e redefinindo N se vir um zero.

pizzapants184
fonte
0

Java , 100 bytes

int[]f(int n){int c=2,r[]=new int[2];for(;n>0;r[c&1]+=n%4==1?(c&2)-1:0,n/=2)c=n%2<1?2:c+1;return r;}

Experimente online!

Freira Furada
fonte
0

R , 54 bytes

function(n,x=rle(n%/%2^(0:log2(n))%%2))sum(1i^x$l*x$v)

Experimente online!

n%/%2^(0:log2(n))%%2calcula um vetor dos dígitos binários. Usando a codificação de execução, usamos R'scomplex tipo para calcular a soma apropriada, multiplicando pelax$values para remover zeros.

Retorna um complexvetor de um elemento.

Giuseppe
fonte