Scambia i bit con i loro vicini


26

Descrizione del compito

Dato un numero intero, scambia i suoi bit (2k – 1) -th e 2k -meno significativi per tutti i numeri interi k> 0 . Questa è la sequenza A057300 nell'OEIS.

(Si presume che il numero abbia "infinitamente molti" zeri iniziali. In pratica, ciò significa semplicemente anteporre un singolo 0 bit a numeri di lunghezza dispari.)

inserisci qui la descrizione dell'immagine

Questo è , quindi vince il codice più breve (in byte).

Casi test

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

5
Possiamo supporre che il numero si adatti come int per cose come i bit shift?
xnor

1
@xnor: penso che sia il consenso predefinito / della comunità (altrimenti le risposte in C ecc. sarebbero sempre sbagliate)? Così sicuro! :)
Lynn,

@Lynn: C richiede unsigned char array_of_bytes[1024]di funzionare come previsto (ovvero essere un bitfield con 1024 * CHAR_BITvoci). Immagino che la maggior parte delle risposte che supportano input di lunghezza arbitraria potrebbero essere uguali CHAR_BIT, sebbene, poiché spostare i bit tra i byte sia ingombrante. Quindi potresti assolutamente mettere un requisito per supportare kfino a una dimensione costante, come 256 o qualcosa di ragionevole per AES, e le lingue senza tipi interi a 256 bit dovrebbero usare i loop. Ciò potrebbe valere la pena considerare i vettori SIMD per una risposta asm x86: P
Peter Cordes,

2
Scambio @Geobits con Minibit
Ottimizzatore

Risposte:


9

Gelatina , 10 9 7 byte

b4d2UFḄ

Provalo online! o verifica tutti i casi di test .

Come funziona

b4d2UFḄ  Main link. Argument: n (integer)

b4       Convert n to base 4.
  d2     Divmod each quaternary digit x by 2, yielding [x : 2, x % 2].
    U    Upend; reverse each pair, yielding [x % 2, x : 2].
     F   Flatten the 2D list of binary digits.
      Ḅ  Convert from binary to integer.

20

Python 2, 26 byte

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

Trucchi!

Say nha forma ...ghfedcbain binario. Quindi, possiamo dividerlo in ogni altro bit come

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

Quindi, il risultato a commutazione di bit spuò essere espresso come s=2*o+e.

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

Preferiamo calcoliamo solo uno di ee o, quindi esprimiamo o=n-2*ee sostituto

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

Quindi, ora resta da esprimere ein termini di n. Il numero M=4**n/3ha forma ...10101010101in binario, che funge da maschera per le cifre dispari. L'esponente ngarantisce che Msia abbastanza lungo. Prendendo bit a bit anddi n/2e questo valore dà ecome desiderato.

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

Possiamo invece esprimere ein termini di o e=(n-o)/2, che dà s=(n+o*3)/2, che salva un byte grazie a un'ottimizzazione di xsot.

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

Grande spiegazione e bel trucco per usare la maschera solo una volta sottraendo n. Tuttavia, preferisco la convenzione di denominazione "dispari" o "pari" al contrario. L'LSB è il bit 0, che è pari (anche se è il primo bit). Nella programmazione SIMD, dove i riordini spesso selezionano elementi con un indice, gli indici contano da 0, quindi è normale considerare l'elemento basso un elemento pari. ad es.[ 3 2 1 0 ]
Peter Cordes,

Ho aggiunto una risposta in C usando la tua espressione. Tutto il merito per il risparmio di byte rispetto alla risposta C di Digital Trauma è dovuto a questo.
Peter Cordes,

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

@PeterCordes Il tuo codice C funziona per me con gcc 4.8.3 e le impostazioni predefinite. f(x){return x+((x&~0U/3)*3)>>1;}restituisce 1 per l'ingresso 2 .
Dennis,

@Dennis: Sì, funziona per me in C, mio ​​male. In realtà stavo testando l'espressione in calc(aka apcalc), non in realtà C. Pensavo che sarei stato bene dal momento che non avevo bisogno del troncamento a 32 bit, o del complemento a due. Non pensavo che l'espressione fosse corretta, quindi ero disposto a credere ai miei test sbagliati. Ma comunque, ho bisogno di un REPL migliore per lo sviluppo di bithacks. Eventuali suggerimenti? (idealmente riga di comando di Linux, come bc -lo calc, ma in realtà esponendo int32_t/ uint32_to qualcosa, non precisione estesa.)
Peter Cordes

10

Funzione C, 38

Bit-giocherellando:

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

Ideone.


O per divertirci:

C funzione ricorsiva, 43

Secondo la formula 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;}

o

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

Ideone.


1
L'intelligente trasformazione dell'espressione di xnor porta questo a 32 byte in C. L'ho pubblicato come risposta separata, poiché è un approccio significativamente diverso.
Peter Cordes

8

CJam, 16 14 13 byte

ri4b4e!2=f=4b

Provalo qui.

Spiegazione

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.

Questo trucco con le permutazioni è molto buono!
Luis Mendo,

7

Pyth, 9 byte

iXjQ4S2)4

Provalo nel compilatore Pyth .

Come funziona

  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 byte

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

Funziona solo fino a 1073741823 a causa delle limitazioni degli interi di JavaScript. 38 36 byte funziona fino a 4294967295:

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

Modifica: salvato 2 byte grazie a @ user81655.

51 byte funziona fino a 4503599627370495:

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

Potrebbe n<<1essere n*2?
user81655

@ user81655 E posso usare n/2anche io ! Non so perché non ci abbia pensato prima.
Neil,

Non ho mai visto >>>... che cos'è?
Tito

@Titus È come >>>ma fa un turno senza segno. >>>0fondamentalmente converte in un numero intero senza segno a 32 bit.
Neil,

5

x86 asm function: 14 byte di codice macchina

Versione uint64_t: 24 byte

x86-64 Convenzione di chiamata SysV ( xin edi), ma lo stesso codice macchina funzionerà anche in modalità 32 bit. (Dove leadecodificherà come lea eax, [edi + eax*2], il che dà risultati identici ).

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 byte

Questo è l' output del compilatore dall'uso dell'eccellente idea di maschera di xnor, una volta al contrario. (E opposta terminologia: il bit basso è il bit 0, che è pari, non dispari.)

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

Non ho trovato alcun miglioramento rispetto a quello che fa il compilatore. Potrei averlo scritto come mov eax, 0x555.../ and eax, edi, ma è della stessa lunghezza.


La stessa funzione per numeri interi a 64 bit richiede 24 byte (vedere il collegamento godbolt). Non vedo alcun modo inferiore a 10 byte movabs rax, 0x55...per generare la maschera in un registro. (Le divistruzioni di x86 sono goffe, quindi la divisione senza segno di tutti per 3 non aiuta.)

Ho creato un loop per generare la maschera in rax, ma è di 10 byte (esattamente la stessa lunghezza della 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 sapessimo che nessuno dei byte esistenti raxha il loro bit basso impostato, potremmo saltare il xor, e questo sarebbe lungo 8 byte.

Una versione precedente di questa risposta aveva un loop di 10 byte che utilizzava l' loopinsn, ma aveva un tempo di esecuzione nel caso peggiore di 0xFFFFFFFFFFFFFF08iterazioni, perché avevo impostato solo cl.


5

Oasis , 17 byte (non concorrenti)

n4÷axxn4÷xxe+3120

Provalo online!

Oasis è un linguaggio disegnato da Adnan specializzato in sequenze.

Attualmente, questa lingua può fare ricorsione e forma chiusa.

Usiamo questa formula: a(4n+k) = 4a(n) + a(k), 0 <= k <= 3

Specificare il caso base è semplice: 3120alla fine significa semplicemente che 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 byte

BP2eP1ePXB

Provalo online!

Versione modificata per generare i primi termini della sequenza ( OEIS A057300 ).

Spiegazione

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 byte

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

Accetta input come argomento della riga di comando, output su STDOUT.

Non è compatibile con Bash perché utilizza una sintassi di conversione di base specifica per 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 byte

. +
$ *
+ `(1 +) \ 1
$ 1x
x1
1
^
X
R` (.) (.)
$ 2 $ 1
1
X@
+ `@ X
X@@
X*(@*)
$ .1
0 $

Suite di test. (Leggermente modificato.)

Bene, solo per divertimento: 7 byte

T`12`21

Prende la base-4 come input e le uscite come base-4.

Provalo online!


4
Sono in conflitto Voglio votare la metà inferiore della tua risposta, ma diminuire la metà superiore.
Dennis,

1
@Dennis Ora ho scambiato quei pezzi.
Leaky Nun,

3

05AB1E, 8 byte

4B12‡4ö

Grazie a @Adnan per -5 byte!

Utilizza la codifica CP-1252.

Provalo online!

Spiegazione:

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

2
Bello, ma puoi sostituirlo 1 2‚2 1‚con 12Âper 8 byte.
Adnan,

Bella risposta! Ecco un'alternativa a 8 byte:4в2‰íJJC
Kevin Cruijssen l'

3

C, 32 30 29 byte

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 copiato dal commento di xsot sulla risposta Python di xnor . Invece di mascherare entrambi i modi, maschera un modo e combina.

Questo si compila allo stesso modo dell'ultima versione che ho testato e funziona (per x fino a 0x3FFFFFFFe per x sopra che fintanto che il bit 30 non è impostato, vedi sotto). Nel codice macchina, ha la stessa lunghezza della mia risposta asm esistente.


La versione precedente cancella sempre il bit più alto del risultato . La migliore versione sicura è di 32 byte:

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

La versione di Python non presenta questo problema, poiché python utilizza tipi interi di precisione arbitraria quando necessario , anziché troncare a un limite superiore fisso.


@Dennis: Argh, sì, grazie. Ho effettuato l'ultima modifica dopo il test e ho perso la differenza nell'output asm. Non c'è da stupirsi che stavo pensando che sembrava sbagliato; Avevo dimenticato che >>era una precedenza così bassa. Non gioco abbastanza spesso per ricordare esattamente quali sono le regole, poiché gli avvisi del compilatore che suggeriscono che i parens in casi pericolosi mi salvino in codice reale. : P
Peter Cordes,

2
Puoi eliminare quello spazio riordinando i termini nell'espressione.
xsot,

2

Javascript (ES6), 113 109 byte

Salvati 4 byte grazie a Upgoat

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

Come funziona

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
)

usa +('0b"+binary_string_here)invece di `parseInt (..., 2)
Downgoat

1

J, 20 byte

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

uso

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

Dov'è >>STDIN ed <<è STDOUT.

Ungolfed

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

Tre forchette.

Nota a margine

Nell'interprete ufficiale, ^:_1 può essere sostituito da inv, salvando 1 byte.

Tuttavia, nessuno degli interpreti online lo implementa.


1

C #, 44 byte

Basato sull'implementazione C.

int f(int n)=>n>3?4*f(n/4)+f(n%4):n%2*2+n/2;

Provalo qui: pad C #


1

INTERCAL , 60 byte

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

Provalo online!

Funziona con numeri interi a 16 bit, con I / O eseguito nel formato più naturale per INTERCAL: l'input è una serie di cifre decimali enunciate in una delle diverse lingue naturali o costruite e l'output è in "numeri romani macellati".

Questa è una di quelle rare sfide in cui gli operatori binari di INTERCAL possono effettivamente essere utilizzati in modo intuitivo, poiché riposizionare i bit è ciò di cui si occupano. Selezionare ( ) e ricollegarli insieme nell'ordine opposto. Fortunatamente per il conteggio dei byte, sebbene gli operatori di INTERCAL non abbiano una precedenza definita (poiché l'obiettivo del linguaggio è di non avere precedenti), si scopre che C-INTERCAL su TIO non richiede molto raggruppamento per questa particolare espressione, costando solo un byte poiché può essere abbreviato .~ ) prende i bit dal suo primo argomento corrispondente a quelli nel suo secondo argomento e li sposta a destra con zero, e mingle ($ ) interlaccia i bit dai suoi argomenti in modo che i bit del primo argomento siano più significativi. Quindi la soluzione semplice è quella di selezionare i bit alternati meno significativi ( .1~#21845), selezionare i bit alternati più significativi (.1~#43690'.!

Con supporto per numeri interi a 32 bit:

INTERCAL , 67 byte

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

Provalo online!

INTERCAL non consente i letterali a 32 bit, il che in realtà rende un po ' più semplice la lettura, poiché significa che le costanti magiche per la selezione di bit alternati devono essere costruite mescolando insieme due letterali a 16 bit, dove ognuno è azzerato e l'altro tutti quelli. (In realtà, anche se ci fossero valori letterali a 32 bit, questo sarebbe comunque più breve. #0$#65535È a due byte di distanza #1431655765, e lo stesso vale per l'altro.) Ciò comunica innaturalmente l'intero processo per INTERCAL.

Un approccio alternativo con uso goffo di sovraccarico di operandi :

INTERCAL , 71 byte

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

Provalo online!

Questo elimina la selezione del tutto dichiarando che :1si .2mescola .3, si imposta :1sull'input e quindi si confonde .3con .2. Da:1 stato sovraccaricato come .2$.3, DO :1 <- :2assegna valori a .2e .3tali che :1acquisisce il valore di :2, il che si traduce nel .2contenere i bit alternati più significativi da :2e .3contenenti i bit alternanti meno significativi. Questo sarebbe il più breve delle due soluzioni a 32 bit di quattro byte se PLEASE WRITE IN :1potesse sostituire PLEASE WRITE IN :2 DO :1 <- :2con sovraccarico :1, maCALCULATINGrisulta essere necessario per l'utilizzo del sovraccarico. Sento anche che potrebbe esserci un modo più breve per eseguire il sovraccarico stesso rispetto all'avvio del programma DO:1<-:1/.2$.3, ma poiché si tratta di INTERCAL, sento anche che non può esserci.


0

Mathematica, 44 byte

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

Stesso approccio della mia risposta CJam: converti in base-4, scambia 1 e 2 secondi, converti indietro. Usa anche il trucco di alephalpha per sostituire FromDigitscon Foldun'operazione per salvare un byte.


0

In realtà, 16 byte

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

Provalo online!

Spiegazione:

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 byte

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

Approccio alternativo basato sulla manipolazione di array anziché sul trucco 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

Spiegazione

([:,_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 byte

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