Codici grigi in aumento


36

introduzione

Un codice grigio è un'alternativa alla rappresentazione binaria in cui un numero viene incrementato alternando solo un bit, anziché una quantità variabile di bit. Ecco alcuni codici grigi insieme ai loro equivalenti decimali e binari:

 decimal | binary | gray
-------------------------
       0 |      0 |    0
-------------------------
       1 |      1 |    1
-------------------------
       2 |     10 |   11
-------------------------
       3 |     11 |   10
-------------------------
       4 |    100 |  110
-------------------------
       5 |    101 |  111
-------------------------
       6 |    110 |  101
-------------------------
       7 |    111 |  100
-------------------------
       8 |   1000 | 1100
-------------------------
       9 |   1001 | 1101
-------------------------
      10 |   1010 | 1111
-------------------------
      11 |   1011 | 1110
-------------------------
      12 |   1100 | 1010
-------------------------
      13 |   1101 | 1011
-------------------------
      14 |   1110 | 1001
-------------------------
      15 |   1111 | 1000

Schema bit bit di un codice grigio

A volte chiamato "binario riflesso", la proprietà di cambiare solo un bit alla volta è facilmente raggiungibile con modelli di bit ciclici per ogni colonna a partire dal bit meno significativo:

bit 0: 0110011001100110011001100110011001100110011001100110011001100110
bit 1: 0011110000111100001111000011110000111100001111000011110000111100
bit 2: 0000111111110000000011111111000000001111111100000000111111110000
bit 3: 0000000011111111111111110000000000000000111111111111111100000000
bit 4: 0000000000000000111111111111111111111111111111110000000000000000
bit 5: 0000000000000000000000000000000011111111111111111111111111111111

...e così via.

Obbiettivo

Data una stringa di input non riempita di un codice grigio, incrementa il codice grigio alternando un singolo carattere nella sequenza o anteponendo un 1(quando si incrementa alla potenza successiva di 2), quindi emette il risultato come un codice grigio non imbottito.

Avvertenze

  • Non preoccuparti di prendere 0o una stringa vuota come input.
  • L'input più basso sarà 1e non c'è limite superiore alla lunghezza della stringa oltre alle limitazioni di memoria imposte dall'ambiente.
  • Per stringa non imbottita, intendo dire che non ci saranno spazi bianchi iniziali o finali (diversi da una nuova riga finale opzionale) e nessun carattere iniziale 0nell'input o nell'output.

Formati I / O

I seguenti formati sono accettati per input e output, ma le stringhe sono incoraggiate rispetto ad altri formati:

  • "bit" più significativo per primo
  • non-riempito array di caratteri ASCII o stringa di '1's e '0's
  • array intero non imbottito di 1s e 0s
  • array booleano non imbottito

Cosa non è permesso:

  • "bit" meno significativo per primo
  • intero decimale, binario o unario
  • struttura dati a lunghezza fissa
  • matrice di caratteri o stringa di indici ASCII non stampabili 1e0

test

input -> output
1 -> 11
11 -> 10
111 -> 101
1011 -> 1001
1111 -> 1110
10111 -> 10110
101100 -> 100100
100000 -> 1100000

Altri test possono essere aggiunti su richiesta.

criteri

Questo è , quindi vince il programma più breve in byte! Tutti i legami verranno spezzati favorendo precedenti invii; si applicano scappatoie standard. La migliore risposta inviata verrà accettata il 9 ottobre 2016 e aggiornata ogni volta che verranno fornite risposte migliori.



Possiamo prendere input come numero?
xnor

1
Meno ovviamente, anche in relazione .
Martin Ender,

1
Posso invertire sia l'input che l'output, ad es. 0011Per 8
Ton Hospel il

1
@TonHospel scusami non ho visto la tua domanda sull'I / O invertito. Come ho detto a 1000000000 la mia risposta è no.
Patrick Roberts,

Risposte:


13

Gelatina , 10 8 byte

Grazie a Dennis per aver salvato 2 byte.

^\Ḅ‘^H$B

Input e output sono elenchi di 0 e 1 secondi.

Provalo online!

Spiegazione

L'inverso del codice Gray è dato da A006068 . Usando questo non abbiamo bisogno di generare un gran numero di codici Gray per cercare l'input. Una classificazione di questa sequenza fornita su OEIS è questa:

a(n) = n XOR [n/2] XOR [n/4] XOR [n/8] ...

Dove []sono le staffe da pavimento. Considera l'esempio della 44cui rappresentazione binaria è 101100. Dividere per 2 e pavimentare è solo uno spostamento a destra, tagliando il bit meno significativo. Quindi stiamo cercando di XOR i seguenti numeri

1 0 1 1 0 0
  1 0 1 1 0
    1 0 1 1
      1 0 1
        1 0
          1

Si noti che la ncolonna th contiene i primi nbit. Quindi, questa formula può essere calcolata in modo banale sull'input binario come riduzione cumulativa di XOR sull'elenco (che fondamentalmente applica XOR a ciascun prefisso dell'elenco e ci fornisce un elenco dei risultati).

Questo ci dà un modo semplice per invertire il codice Gray. Successivamente, incrementiamo semplicemente il risultato e lo riconvertiamo nel codice Gray. Per l'ultimo passaggio utilizziamo la seguente definizione:

a(n) = n XOR floor(n/2)

Per fortuna, Jelly sembra bloccare automaticamente gli input quando cerca di XOR. Comunque, ecco il codice:

^\          Cumulative reduce of XOR over the input.
  Ḅ         Convert binary list to integer.
   ‘        Increment.
    ^H$     XOR with half of itself.
       B    Convert integer to binary list.

Non hai bisogno del Ḟ$; operatori bit per bit espressi in int .
Dennis,

@Dennis Grazie, l'ho scoperto mentre scrivevo. :)
Martin Ender,

@MartinEnder L'intero che converte internamente in un intero grande?
Patrick Roberts,

@PatrickRoberts sì, se necessario - è Python sotto il cofano.
Jonathan Allan,

Bella analisi e spiegazione.
Wayne Conrad,

8

JavaScript (ES6), 58 byte

s=>s.replace(s.split`1`.length%2?/.$/:/.?(?=10*$)/,c=>1-c)

Attiva o disattiva direttamente il bit appropriato. Spiegazione: Come mostrato nella risposta di MartinEnder ♦, ogni bit in un codice Gray decodificato è lo XOR, o parità, cumulativo di se stesso e i bit alla sua sinistra. Abbiamo quindi bisogno di aumentare il numero che provoca un'increspatura di carry che sposta tutti gli 1 bit più a destra su 0 e quindi il successivo 0 bit su 1. La ricodifica provoca un codice con solo una posizione di 0 bit attivata. Se la parità di tutti i 1 bit è pari, allora il bit più a destra è 0 e quindi togliamo solo l'ultimo bit. Se la parità di tutti i 1 bit è dispari, i bit più a destra sono 1 e dobbiamo trovare l'ultimo 1 bit. Questo è ora l'ultimo dei bit trasportati, quindi il bit che dobbiamo attivare è il bit successivo da destra.


Metodo molto bello. È il primo ?a /.?(?=10*$)/veramente necessario? Oh non importa. Sì. :-)
Arnauld

8

Perl, 27 25 byte

Include +1 per -p

Fornire una stringa di input su STDIN, ad es

gray.pl <<< 1010

gray.pl:

#!/usr/bin/perl -p
s%(10*\K1(\K0)*)*%1-$&%e

Perl non ha interi economici a precisione infinita. Quindi attiva / disattiva direttamente il bit giusto che è quello appena prima di dove si troverebbe l'ultimo 1 dispari.


1
Wow, \Gti semplifica davvero le cose!
Neil,

1
D'altra parte, \Krende le cose ancora più facili per te.
Neil,

Haaaaa ... Ora voglio vedere anche l' \Gimplementazione.
Magic Octopus Urn

2
@carusocomputing Puoi visualizzare le versioni precedenti di un invio facendo clic sul collegamento modificato
Ton Hospel

6

Haskell, 118 115 108 byte

g 0=[""]
g n|a<-g$n-1=map('0':)a++map('1':)(reverse a)
d=dropWhile
f s=d(=='0')$(d(/='0':s)$g$1+length s)!!1

Provalo su Ideone.
Approccio ingenuo: ggenera l'insieme di tutti i codici grigi con lunghezza n(con 0-padding), fchiama gcon length(input)+1, rimuove tutti gli elementi fino a quando non 0<inputstring>viene trovato e restituisce l'elemento successivo (troncando un possibile inizio 0).


1
Buona prima risposta! Spero di poterne ottenere presto altri più efficienti.
Patrick Roberts,

5

MATL , 18 byte

ZBtE:t2/kZ~tb=fQ)B

Provalo online! Oppure verifica tutti i casi di test .

Spiegazione

Consentire a ( n ) di indicare la sequenza di numeri interi corrispondenti ai codici Gray ( OEIS A003188 ). Il programma utilizza la caratterizzazione a ( n ) = n XOR floor ( n / 2), dove XOR è bit-saggio.

In sostanza, il codice converte l'input in un numero intero a 0 , trova quel numero intero nella sequenza e quindi seleziona il termine successivo. Ciò richiede la generazione di un numero sufficientemente ampio di termini della sequenza a ( n ). Si scopre che 2 · a 0 è sufficientemente grande. Ciò deriva dal fatto che il codice Gray a ( n ) non ha mai più cifre binarie di n .

Prendiamo l'input '101'come esempio.

ZB      % Input string implicitly. Convert from binary string to integer
        %   STACK: 5
t       % Duplicate
        %   STACK: 5, 5
E       % Multiply by 2. This is the number of terms we'll generate from the sequence
        %   STACK: 5, 10
:       % Range
        %   STACK: 5, [1 2 3 4 5 6 7 8 9 10]
t       % Duplicate
        %   STACK: 5, [1 2 3 4 5 6 7 8 9 10], [1 2 3 4 5 6 7 8 9 10]
2/k     % Divide by 2 and round down, element-wise
        %   STACK: 5, [1 2 3 4 5 6 7 8 9 10], [0 1 1 2 2 3 3 4 4 5]
Z~      % Bit-wise XOR, element-wise
        %   STACK: 5, [1 3 2 6 7 5 4 12 13 15]
t       % Duplicate
        %   STACK: 5, [1 3 2 6 7 5 4 12 13 15], [1 3 2 6 7 5 4 12 13 15]
b       % Bubble up
        %   STACK: [1 3 2 6 7 5 4 12 13 15], [1 3 2 6 7 5 4 12 13 15], 5
=       % Equality test, element-wise
        %   STACK: [1 3 2 6 7 5 4 12 13 15], [0 0 0 0 0 1 0 0 0 0]
f       % Find: yield (1-based) index of nonzero values (here there's only one)
        %   STACK: [1 3 2 6 7 5 4 12 13 15], 6
Q       % Increase by 1
        %   STACK: [1 3 2 6 7 5 4 12 13 15], 7
)       % Apply as index
        %   STACK: 4
B       % Convert to binary array
        %   STACK: [1 0 0]
        % Implicitly display

Ho notato che l'output è composto da caratteri delimitati da spazi ... stampa una sorta di array?
Patrick Roberts,

@PatrickRoberts Sì, esattamente. Ho pensato che fosse accettabile, vero?
Luis Mendo,

Lo accetterò così com'è. Ho già allentato i miei requisiti sul formato I / O, quindi non c'è motivo di renderlo più rigoroso. Bel lavoro.
Patrick Roberts,

5

CJam (19 byte)

{_2b__(^@1b1&*)^2b}

Demo online . Questo è un blocco (funzione) anonimo da array di bit a array di bit, che la demo esegue in un ciclo.

Funziona secondo il semplice principio che se il numero di bit impostati è pari dovremmo attivare il bit meno significativo, altrimenti dovremmo spostare il bit a sinistra del bit impostato meno significativo. L'identificazione effettiva di quel bit risulta molto più semplice utilizzando l'hacking bit su un numero intero piuttosto che utilizzare l'elenco dei bit.

Dissezione

{         e# Declare a block:
  _2b     e#   Convert the bit array to a binary number
  __(^    e#   x ^ (x-1) gives 1s from the least significant set bit down
  @1b1&   e#   Get the parity of the number of set bits from the original array
  *       e#   Multiply: if we have an even number of set bits, we get 0;
          e#   otherwise we have 2**(lssb + 1) - 1
  )^      e#   Increment and xor by 1 or 2**(lssb + 1)
  2b      e#   Base convert back to a bit array
}

Lavorando esclusivamente con l'array di bit, penso che sia necessario invertirlo: lavorare con l'estrema sinistra 1è molto più semplice di quello della destra. Il migliore che ho trovato finora è (24 byte):

{W%_1b)1&1$+1#0a*1+.^W%}

Approccio alternativo (19 byte)

{[{1$^}*]2b)_2/^2b}

Questo converte dal codice Gray in indice, incrementa e torna al codice Gray.


5

JavaScript (ES6), 53 byte (non concorrenti)

Una funzione ricorsiva che crea tutti i codici grigi fino a quando non viene trovato l'input, quindi si interrompe alla successiva iterazione.

Il massimo input possibile dipende dal limite di ricorsione del browser (circa 13 bit in Firefox e 15 bit in Chrome).

f=(s,n=1)=>(b=(n^n/2).toString(2),s)?f(b!=s&&s,n+1):b

console.log(f("1"));      // -> 11
console.log(f("11"));     // -> 10
console.log(f("111"));    // -> 101
console.log(f("1011"));   // -> 1001
console.log(f("1111"));   // -> 1110
console.log(f("10111"));  // -> 10110
console.log(f("101100")); // -> 100100
console.log(f("100000")); // -> 1100000


Temo che questo invio non sia idoneo, poiché il metodo non funziona per lunghezze di stringa illimitate. Si prega di passare a non competitivo se si desidera mantenere questa risposta qui.
Patrick Roberts,

@PatrickRoberts - Sicuro. Ciò ha senso.
Arnauld,

@PatrickRoberts Davvero? In che modo un limite di ricorsione non rientra tra i "limiti di memoria imposti dall'ambiente"?
Sanchises,

@sanchises Mi riferivo alla memoria heap, ma più precisamente, questo programma ricorre per ogni possibile codice grigio fino a quello in fase di test, il che è estremamente inefficiente. Tecnicamente questo potrebbe essere presentato come "Node.js 6.5" e --harmonyaggiunto per byte di penalità al fine di avere accesso all'ottimizzazione della ricorsione delle chiamate di coda, che sembra essere possibile qui.
Patrick Roberts,

@sanchises Guardando oltre la mia risposta, questa era una discussione scadente. Il problema principale è che la limitazione non è imposta dall'ambiente, è imposta dall'algoritmo. Ci sono altre risposte che valgono per ogni bit piuttosto che per ogni valore incrementale, e trovo che siano più accettabili poiché funziona per un intervallo di valori molto più ampio.
Patrick Roberts,

2

Retina, 25 byte

^(10*10*)*
$1:
1:
0
.?:
1

Sono sicuro che dovrebbe esserci un modo migliore per farlo ...


Hai davvero bisogno del ^?
Ton Hospel,

@TonHospel Il regex ha cercato di abbinarsi ovunque senza di essa. (Sostituisci la modalità predefinita con una sostituzione globale.)
Neil,

2

05AB1E , 12 byte

Utilizza la codifica CP-1252 .

CÐ<^¹SOÉ*>^b

Provalo online!

Spiegazione

Esempio per l'ingresso 1011 .

C              # convert to int (bigint if necessary)
               # STACK: 11
 Ð             # triplicate
               # STACK: 11, 11, 11
  <            # decrease by 1
               # STACK: 11, 11, 10
   ^           # XOR
               # STACK: 11, 1
    ¹          # push first input
               # STACK: 11, 1, 1011
     S         # split to list
               # STACK: 11, 1, [1,0,1,1]
      O        # sum
               # STACK: 11, 1, 3
       É       # mod 2
               # STACK: 11, 1, 1
        *      # multiply
               # STACK: 11, 1
         >     # increase by 1
               # STACK: 11, 2
          ^    # XOR
               # STACK: 9
           b   # convert to binary
               # STACK: 1001
               # implicitly print top of stack

2

Python 2.7, 68 caratteri

def f(s):i=long(s,2);print bin(i^(1,(i&-i)<<1)[s.count('1')&1])[2:]

Python 3, 68 caratteri

def f(s):i=int(s,2);print(bin(i^(1,(i&-i)<<1)[s.count('1')&1])[2:])

Questa funzione converte la stringa binaria data in un numero intero, quindi xo l'ultimo bit se il numero di bit impostati nella stringa originale è pari, oppure scambia il bit a sinistra del bit impostato più a destra se il numero di bit impostati nell'originale la stringa è dispari. Quindi converte il risultato in una stringa binaria e rimuove il 0bprefisso booleano.


1
Puoi salvare 1 byte rimuovendo lo spazio dopo def f(s):e (supponendo Python 2) un altro usando printinvece di return.
ElPedro,

@ElPedro Grazie, ho anche applicato un trucco per le condizioni e ho preso in considerazione la dimensione della mano sinistra di un xor per salvare alcuni caratteri aggiuntivi :)
Morwenn,

L'ho appena visto. Bella risposta :-)
ElPedro

Um .. controllando la documentazione di Python, sembra che int()generi un numero intero a 32 bit, anche se il mio requisito è che tu incrementi qualsiasi stringa di lunghezza. Non sono sicuro che questo si qualifichi come un valido contributo
Patrick Roberts,

1
@PatrickRoberts Controllerò più tardi. longinvece di intpotrebbe risolvere il problema.
Morwenn,

2

C ++, 205 byte

#include <string>
std::string g(std::string s){int i,z;if(s=="1")return"11";for(i=z=0;i<s.length();i++)if(s[i]=='1')z++;i--;if(z%2){char c=s[i];s.erase(i);s=g(s);s+=c;}else{s[i]=s[i]==49?48:49;}return s;}

Descrizione: i numeri pari ne hanno un numero pari. zConta variabile quelli; if zis even ( z mod 2 = z%2 = 0- else branch), modifica l'ultimo bit; se zè dispari, chiama di nuovo questa funzione senza l'ultimo carattere e calcola il nuovo valore, quindi aggiungi l'ultimo carattere in seguito.

Fai clic qui per provarlo per i casi di test.


Grazie per la sua iscrizione. Se potessi fornire una breve descrizione del tuo approccio e un link a una compilation online di questo come una demo, lo apprezzerei molto.
Patrick Roberts,

1
@PatrickRoberts Aggiunto il collegamento e la descrizione come richiesto.
AlexRacer,

2

Lotto, 199 197 byte

@echo off
set/ps=
set r=
set t=%s:0=%
if 1%t:11=%==1 goto g
:l
set b=%s:~-1%
set s=%s:~,-1%
set r=%b%%r%
if %b%==0 goto l
if 0%s%==0 set s=0
:g
set/ab=1-%s:~-1%
echo %s:~,-1%%b%%r%

Legge l'input da STDIN in variabile s. Rimuove gli 0 e esegue un controllo di parità sugli 1 e se esiste un numero dispari, rimuove gli 0 più a destra in un ciclo, arrestandosi quando rimuove uno 1. scontiene quindi il prefisso di parità pari e ril resto della stringa. sè impostato su zero se era vuoto in modo che la sua ultima cifra potesse essere attivata e quindi tutto è concatenato.


1

In realtà, 20 19 13 byte

Basato sulla risposta di Jelly di Martin Ender con la mia versione di "riduzione cumulativa di XOR sull'input". Suggerimenti di golf benvenuti. Provalo online!

σ1♀&2@¿u;½≈^├

Ungolfing

      Implicit input a as a list, such as [1,0,1,1,0,0].
σ     Get the cumulative sums of a.
1♀&   Map x&1 (equivalent to x%2) over every member of the cumulative sum.
2@¿   Convert from binary to decimal.
u     Increment x.
;½≈   Duplicate and integer divide by 2.
^     XOR x and x//2.
├     Convert to binary to obtain our incremented Gray code.
      Implicit return as a string, such as "100100".

1

J, 38 bytes

[:#:@(22 b.<.@-:)@>:@#.[:22 b./[:#:#.\

Try it online!

This is essentially Martin's algorithm in J.

Note that 22 b. is XOR.

                                    [: #: #.\   Creates the prefixes of the input
                                                converts to a number, then converts
                                                back to binary.  Needed to get the
                                                padding on the left.

                          [: 22 b./             Reduce the rows of the resulting 
                                                matrix with XOR, giving us the 
                                                normal binary
                      @#.                       Convert to int and...
                   @>:                          Increment and...
      (22 b. <.@-:)                             XOR that with its own floored half
[: #:@                                          And turn the result back to binary

Nice job, dude!
Patrick Roberts
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.