Troque bits com seus vizinhos


26

Descrição da tarefa

Dado um número inteiro, troque seus bits (2k – 1) -th e 2k -th menos significativos para todos os números inteiros k> 0 . Esta é a sequência A057300 no OEIS.

(Supõe-se que o número tenha "infinitos" zeros à esquerda. Na prática, isso significa simplesmente acrescentar um único 0 bit a números de comprimento ímpar.)

insira a descrição da imagem aqui

Isso é , então o código mais curto (em bytes) vence.

Casos de teste

0 -> 0
1 -> 2
9 -> 6
85 -> 170
220 -> 236
1827 -> 2835
47525 -> 30298

5
Podemos assumir que o número se encaixa como int para coisas como mudanças de bits?
xnor

1
@ xnor: Eu acho que esse é o padrão / consenso da comunidade (caso contrário, as respostas em C etc. sempre estariam erradas)? Tão certo! :)
Lynn

@ Lynn: C requer unsigned char array_of_bytes[1024]que funcione da maneira que você espera (por exemplo, seja um campo de bits com 1024 * CHAR_BITentradas). Eu imagino que a maioria das respostas que suportam entradas de comprimento arbitrário presumiria que CHAR_BITera uniforme, já que a troca de bits entre bytes é complicada. Portanto, você poderia absolutamente exigir um ktamanho constante, como 256 ou algo razoável para o AES, e idiomas sem tipos inteiros de 256 bits teriam que usar loops. Isso pode fazer SIMD vetores vale a pena considerar uma resposta x86 asm: P
Peter Cordes

2
Eu troco @Geobits por Minibits
Optimizer

Respostas:



20

Python 2, 26 bytes

lambda n:2*n-3*(4**n/3&n/2)

Truques!

Say ntem forma ...ghfedcbaem binário. Então, podemos dividi-lo em qualquer outro

n   = o + 2*e
n   = ...hgfedcba
o   = ...0g0e0c0a
2*e = ...h0f0d0b0

Em seguida, o resultado de comutação de bits spode ser expresso como s=2*o+e.

s   = 2*o + e
s   = ...ghefcdab
2*o = ...g0e0c0a0
e   = ...0h0f0d0b

Preferimos calcular apenas um de ee o, portanto, expressamos o=n-2*ee substituímos

s=2*(n-2*e)+e = 2*n-3*e

Então, agora resta expressar eem termos de n. O número M=4**n/3tem forma ...10101010101em binário, que serve como uma máscara para os dígitos ímpares. O expoente ngarante que Mseja longo o suficiente. Tomando o bit a bit andde n/2e esse valor fornece ecomo desejado.

n/2     = ...hgfedcb
M       = ...1010101
n/2 & M = ...h0f0d0b = e

Em vez disso, podemos expressar eem termos de o e=(n-o)/2, o que dá s=(n+o*3)/2, o que economiza um byte, graças a uma otimização do xsot.

lambda n:n+(n&4**n/3)*3>>1

Ótima explicação e bom truque para usar a máscara apenas uma vez subtraindo de n. No entanto, prefiro a convenção de nomenclatura de bits "ímpar" vs. "par" oposta. O LSB é o bit 0, que é par (mesmo que seja o primeiro bit). Na programação do SIMD, em que as aleatórias geralmente selecionam elementos com um índice, os índices contam de 0; portanto, é normal considerar o elemento baixo como um elemento par. por exemplo[ 3 2 1 0 ]
Peter Cordes 06/06

Eu adicionei uma resposta C usando sua expressão. Todo o crédito pela economia de bytes versus a resposta C do Digital Trauma é devido a isso.
Peter Cordes

2
26:lambda n:n+(n&4**n/3)*3>>1
xsot 6/06/16

@PeterCordes Seu código C funciona para mim com o gcc 4.8.3 e as configurações padrão. f(x){return x+((x&~0U/3)*3)>>1;}retorna 1 para a entrada 2 .
Dennis

@Dennis: Sim, funciona para mim em C, meu mal. Na verdade, eu estava testando a expressão em calc(também conhecido como apcalc), e não na C. Eu pensei que ficaria bem, já que não precisava de truncamento para 32 bits, ou o complemento de dois. Não achei que a expressão parecesse correta, então estava disposta a acreditar nos meus testes errados. Mas de qualquer maneira, estou precisando de um REPL melhor para o desenvolvimento de bithacks. Alguma sugestão? (idealmente linha de comando Linux, como bc -lou calc, mas na verdade expondo int32_t/ uint32_tou algo assim, não precisão estendida.)
Peter Cordes

10

Função C, 38

Correção de bits:

f(x){return(x&~0U/3*2)/2+(x&~0U/3)*2;}

Ideone.


Ou pela diversão:

Função recursiva C, 43

De acordo com a fórmula OEIS ,a(4n+k) = 4a(n) + a(k), 0 <= k <= 3

f(x){return x>3?4*f(x/4)+f(x%4):x%3?3-x:x;}

ou

f(x){return x>3?4*f(x/4)+f(x%4):x%2*2+x/2;}

Ideone.


1
A transformação inteligente da expressão do xnor reduz isso para 32 bytes em C. Eu a publiquei como uma resposta separada, pois é uma abordagem significativamente diferente.
Peter Cordes

8

CJam, 16 14 13 bytes

ri4b4e!2=f=4b

Teste aqui.

Explicação

ri  e# Read input and convert to integer.
4b  e# Get base-4 digits.
4e! e# Push all permutations of [0 1 2 3].
2=  e# Select the third one which happens to be [0 2 1 3].
f=  e# For each base-4 digit select the value at that position in the previous
    e# list, which swaps 1s and 2s.
4b  e# Convert back from base 4.

Esse truque com as permutações é muito bom!
Luis Mendo

7

Pitão, 9 bytes

iXjQ4S2)4

Experimente no Compilador Pyth .

Como funciona

  jQ4      Convert the input (Q) to base 4.
 X   S2)   Translate [1, 2] to [2, 1].
i       4  COnvert from base 4 to integer.

5

JavaScript (ES6), 32 30 bytes

(n,m=0x55555555)=>n*2&~m|n/2&m

Funciona apenas até 1073741823 devido às limitações de números inteiros do JavaScript. 38 36 bytes funcionam até 4294967295:

(n,m=0x55555555)=>(n*2&~m|n/2&m)>>>0

Editar: salvou 2 bytes graças a @ user81655.

51 bytes funcionam até 4503599627370495:

n=>parseInt(n.toString(4).replace(/1|2/g,n=>3-n),4)

Poderia n<<1ser n*2?
user81655

@ user81655 E eu também posso usar n/2! Não sei por que não pensei nisso antes.
Neil

Eu nunca vi >>>... o que é isso?
Titus

@Titus É como, >>>mas faz uma mudança sem sinal. >>>0basicamente converte em um inteiro não assinado de 32 bits.
Neil

5

Função x86 asm: 14 bytes de código de máquina

Versão uint64_t: 24 bytes

Convenção de chamada x86-64 SysV ( xpol edi), mas esse mesmo código de máquina também funcionará no modo 32 bits. (Onde o leadecodificará como lea eax, [edi + eax*2], o que dá resultados idênticos ).

0000000000000040 <onemask_even>:
  40:   89 f8                   mov    eax,edi
  42:   25 55 55 55 55          and    eax,0x55555555
  47:   29 c7                   sub    edi,eax
  49:   d1 ef                   shr    edi,1
  4b:   8d 04 47                lea    eax,[rdi+rax*2]
  4e:   c3                      ret    
4f: <end>

0x4f - 0x40 = 14 bytes

Esta é a saída do compilador do uso da excelente idéia de máscara única do xnor da maneira oposta. (E terminologia oposta: o bit baixo é o bit 0, que é par, não é ímpar.)

unsigned onemask_even(unsigned x) {
  unsigned emask = ~0U/3;
  unsigned e = (x & emask);
  return e*2 + ((x - e) >> 1);
}

Não encontrei nenhuma melhoria sobre o que o compilador faz. Eu poderia ter escrito como mov eax, 0x555.../ and eax, edi, mas esse é o mesmo comprimento.


A mesma função para números inteiros de 64 bits leva 24 bytes (veja o link godbolt). Não vejo uma maneira menor que 10 bytes movabs rax, 0x55...para gerar a máscara em um registro. (As divinstruções do x86 são desajeitadas, portanto a divisão não assinada de todos por um por três não ajuda.)

Eu criei um loop para gerar a máscara em rax, mas são 10 bytes (exatamente o mesmo comprimento que o mov imm64).

# since 0x55 has its low bit set, shifting it out the top of RAX will set CF
0000000000000000 <swap_bitpairs64>:
   0:   31 c0                   xor    eax,eax      ; old garbage in rax could end the loop early
0000000000000002 <swap_bitpairs64.loop>:
   2:   48 c1 e0 08             shl    rax,0x8
   6:   b0 55                   mov    al,0x55      ; set the low byte
   8:   73 f8                   jnc    2 <swap_bitpairs64.loop>  ; loop until CF is set
000000000000000a <swap_bitpairs64.rest_of_function_as_normal>:
 # 10 bytes, same as   mov  rax, 0x5555555555555555
 # rax = 0x5555...
   a:   48 21 f8                and    rax,rdi
   ...

Se soubéssemos que nenhum dos bytes existentes raxtem seu bit baixo definido, poderíamos pular o arquivo xore isso teria 8 bytes de comprimento.

Uma versão anterior desta resposta tinha um loop de 10 bytes usando o loopinsn, mas tinha um pior tempo de execução de 0xFFFFFFFFFFFFFF08iterações, porque eu apenas o defini cl.


5

Oásis , 17 bytes (não competitivo)

n4÷axxn4÷xxe+3120

Experimente online!

Oasis é uma linguagem projetada por Adnan, especializada em seqüências.

Atualmente, esse idioma pode fazer recursão e formulário fechado.

Nós usamos esta fórmula: a(4n+k) = 4a(n) + a(k), 0 <= k <= 3

Especificar o caso base é simples: 3120no final significa simplesmente isso a(0)=0, a(1)=2, a(2)=1, a(3)=3.

n4÷axxn4÷xxe+3120
                0  a(0) = 0
               2   a(1) = 2
              1    a(2) = 1
             3     a(3) = 3

n                  push n (input)
 4÷                integer-divide by 4
   a               a(n/4)
    xx             double twice; multiply by 4
                   now we have 4a(n/4)
      n            push n (input)
       4÷xx        integer-divide by 4 and then multiply by 4
                   since there is no modulo currently, n%4
                   is built as n-(n/4*4)
           e       we should have done a(n-(n/4*4)), but this
                   is a shortcut for a(n-x) where x is the top
                   of stack. Therefore, we now have a(n-n/4*4)
                   which is a(n%4).
            +      add.

4

MATL , 10 bytes

BP2eP1ePXB

Experimente online!

Versão modificada para gerar os primeiros termos da sequência ( OEIS A057300 ).

Explicação

B     % Take input implicitly. Convert to binary array
P     % Flip
2e    % Convert to two-row 2D array, padding with a trailing zero if needed. 
      % Because of the previous flip, this really corresponds to a leading zero
P     % Flip each column. This corresponds to swapping the bits
1e    % Reshape into a row
P     % Flip, to undo the initial flipping
XB    % Convert from binary array to number. Display implicitly

3

zsh, 28 bytes

<<<$[`tr 12 21<<<$[[#4]$1]`]

Recebe a entrada como argumento da linha de comando e sai em STDOUT.

Não é compatível com o Bash porque usa a sintaxe de conversão de base específica do zsh.

                       $1     input (first command line argument)
                 $[      ]    arithmetic expansion
                   [#4]       output in base 4
              <<<             pass the result of this to...
      tr                      the `tr' command
         12 21                and replace 1s with 2s, 2s with 1s
     `                    `   evaluate the result...
   $[                      ]  in another arithmetic expansion, to convert back
                                to base 10
<<<                           output the result on STDOUT

3

Retina, 70 bytes

. +
$ *
+ `(1 +) \ 1
$ 1x
x1
1
^
x
r` (.) (.)
$ 2 $ 1
1
x @
+ `@ x
x @@
x * (@ *)
$ 0,1
0 $

Suíte de teste. (Ligeiramente modificado.)

Bem, apenas por diversão: 7 bytes

T`12`21

Toma a base-4 como entrada e as saídas como base-4.

Experimente online!


4
Estou em conflito. Eu quero votar na metade inferior da sua resposta, mas na votação na metade superior.
Dennis

1
@ Dennis Agora eu tenho esses bits trocados.
Freira vazada

3

05AB1E, 8 bytes

4B12‡4ö

Graças a @Adnan por -5 bytes!

Usa a codificação CP-1252.

Experimente Online!

Explicação:

4B       - Take input and convert to base 4.
  12Â    - Push 12 bifurcated.
     ‡   - Transliterate [1, 2] to [2, 1].
      4ö - Convert to base 10.

2
Bom, mas você pode substituir 1 2‚2 1‚com 12Âpor 8 bytes.
Adnan

Boa resposta! Aqui está uma alternativa de 8 bytes:4в2‰íJJC
Kevin Cruijssen

3

C, 32 30 29 bytes

f(x){return(x&~0U/3)*3+x>>1;}                // 30 bit version, see below

// less golfed:
f(x){return ((x & 0x55555555)*3 + x) >>1;}   //  >> is lower precedence than +

Algoritmo copiado do comentário do xsot na resposta Python do xnor . Em vez de mascarar nos dois sentidos, mascarar de um lado e combinar.

Isso é compilado da mesma forma que a última versão que eu testei e funciona (para x até x 0x3FFFFFFFe acima disso, desde que o bit 30 não esteja definido, veja abaixo). No código da máquina, tem o mesmo tamanho da minha resposta asm existente.


A versão acima sempre limpa a parte alta do resultado . A melhor versão segura é de 32 bytes:

g(x){return 2*x-3*(x/2U&~0U/3);}   // safe 32bit version, works for all x

A versão do Python não tem esse problema, porque o python usa tipos inteiros de precisão arbitrária quando necessário , em vez de truncar para um limite superior fixo.


@ Dennis: Argh, sim, obrigado. Fiz a última alteração após o teste e perdi a diferença na saída asm. Não é de admirar que eu estivesse pensando que parecia errado; Eu tinha esquecido que >>era uma precedência tão baixa. Não jogo com frequência suficiente para lembrar exatamente quais são as regras, pois os avisos do compilador que sugerem parênteses em casos perigosos me salvam em código real. : P
Peter Cordes 06/06

2
Você pode eliminar esse espaço reorganizando os termos na expressão.
xsot

2

Javascript (ES6), 113 109 bytes

Economizou 4 bytes graças ao Upgoat

n=>+('0b'+/(..)+$/.exec('0'+n.toString`2`)[0].split``.reduce((p,c)=>p.length-1?[p.join(c)]:[p[0],c],[''])[0],2)

Como funciona

n=>+('0b'+                              //parse as binary literal
    /(..)+$/.exec('0'+n.toString`2`)[0] //convert to binary string with an even number of digits
        .split``                        //convert to array
        .reduce((p,c)=>p.length-1?[p.join(c)]:[p[0],c],[''])
                                        //swap all numbers
)

use em +('0b"+binary_string_here)vez de `parseInt (..., 2)
Downgoat 03/06

1

J, 20 bytes

4#.0 2 1 3{~4#.^:_1]

Uso

>> f =: 4#.0 2 1 3{~4#.^:_1]
>> f 85
<< 170

Onde >>está STDIN e <<está STDOUT.

Ungolfed

to_base   =: 4 #.^:_1 ]
transpose =: 0 2 1 3 {~ to_base
from_base =: 4 #. transpose

Três garfos.

Nota

No intérprete oficial, ^:_1pode ser substituído por inv, economizando 1 byte.

No entanto, nenhum dos intérpretes online implementa isso.



1

INTERCAL , 60 bytes

DOWRITEIN.1PLEASE.1<-!1~#21845'$.1~#43690DOREADOUT.1DOGIVEUP

Experimente online!

Funciona para números inteiros de 16 bits, com E / S executada no formato mais natural para INTERCAL: a entrada é uma série de dígitos decimais digitados em um dos vários idiomas naturais ou construídos e a saída é em "números romanos massacrados".

Esse é um daqueles raros desafios em que os operadores binários da INTERCAL podem realmente ser utilizados intuitivamente, pois é o reposicionamento de bits. Selecione ( ) e intercale-os novamente na ordem oposta. Felizmente para a contagem de bytes, embora os operadores da INTERCAL não tenham precedência definida (como o objetivo do idioma é não ter precedentes), o C-INTERCAL no TIO não exige muito agrupamento para essa expressão em particular, custando apenas um byte, pois pode ser abreviado .~ ) pega os bits do seu primeiro argumento correspondente aos do segundo argumento e os coloca à direita com zeros, e mingle ( $) intercala os bits de seus argumentos, de modo que os bits do primeiro argumento sejam mais significativos. Portanto, a solução direta é selecionar os bits alternativos menos significativos (.1~#21845 ), selecionar os bits alternativos mais significativos (.1~#43690'.!

Com suporte para números inteiros de 32 bits:

INTERCAL , 67 bytes

DOWRITEIN:1PLEASE:1<-':1~#0$#65535'$:1~#65535$#0DOREADOUT:1DOGIVEUP

Experimente online!

Não INTERCAL não permite literais de 32 bits, o que realmente torna este um pouco mais fácil de ler, uma vez que significa as constantes mágicas para selecionar pedaços alternados tem que ser construído por mistura dois literais de 16 bits juntos, onde um é todos os zeros e os outros de todos. (Na verdade, mesmo que houvesse literais de 32 bits, isso ainda seria mais curto. #0$#65535Estão dois bytes desativados #1431655765e o mesmo vale para o outro.) Isso comunica todo o processo de maneira não natural para INTERCAL.

Uma abordagem alternativa com o uso desajeitado de sobrecarga de operando :

INTERCAL , 71 bytes

DO:1<-:1/.2$.3PLEASEWRITEIN:2DO:1<-:2PLEASE:2<-.3$.2DOREADOUT:2DOGIVEUP

Experimente online!

Isso acaba com a seleção, declarando que :1é .2mesclado .3, configurando :1a entrada e, em seguida, produzindo .3mesclado .2. Uma vez que :1foi sobrecarregado como .2$.3, DO :1 <- :2valores atribui a .2e .3de tal modo que :1adquire o valor de :2, o que resulta em .2contendo os bits mais significativos alternadas a partir de :2e .3contendo os bits menos significativos alternadas. Essa seria a menor das duas soluções de 32 bits em quatro bytes se PLEASE WRITE IN :1pudesse substituir PLEASE WRITE IN :2 DO :1 <- :2por sobrecarregada:1 , masCALCULATINGacaba sendo necessário para o uso de sobrecarga. Também sinto que pode haver uma maneira mais curta de realizar a sobrecarga do que iniciar o programa DO:1<-:1/.2$.3, mas como isso é INTERCAL, também sinto que não pode haver.


0

Mathematica, 44 bytes

Fold[3#+##&,#~IntegerDigits~4/.{1->2,2->1}]&

A mesma abordagem da minha resposta CJam: converter para base-4, trocar 1s e 2s, converter novamente. Ele também usa o truque de alefhalpha para substituir FromDigitspor uma Foldoperação para salvar um byte.


0

Na verdade, 16 bytes

4@¡"21""12"(t4@¿

Experimente online!

Explicação:

4@¡"21""12"(t4@¿
4@¡               base 4 representation of n
   "21""12"(t     translate (swap 1s and 2s)
             4@¿  base 4 to decimal

0

J, 22 bytes

([:,_2|.\,&0)&.(|.@#:)

Abordagem alternativa baseada na manipulação de array em vez do truque da base 4.

Uso

   f =: ([:,_2|.\,&0)&.(|.@#:)
   (,.f"0) 0 1 9 85 220 1827 47525
    0     0
    1     2
    9     6
   85   170
  220   236
 1827  2835
47525 30298

Explicação

([:,_2|.\,&0)&.(|.@#:)  Input: n
                   #:   Get the value as a list of base 2 digits
                |.@     Reverse it
(           )&.         Apply to the list of base 2 digits
         ,&0            Append a zero to the end of the list
    _2  \               Split the list into nonoverlapping sublists of size 2
      |.                Reverse each sublist
 [:,                    Flatten the list of sublists into a list
             &.(    )   Apply the inverse of (reversed base 2 digits)
                        to convert back to a number and return it

0

REXX, 88 bytes

n=x2b(d2x(arg(1)))
o=0
do while n>''
  parse var n a+1 b+1 n
  o=o||b||a
  end
say x2d(b2x(o))
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.