Incrémentation des codes gris


36

introduction

Un code Gray est une alternative à la représentation binaire dans laquelle un nombre est incrémenté en ne basculant qu'un bit, plutôt qu'une quantité variable de bits. Voici quelques codes gris ainsi que leurs équivalents décimaux et binaires:

 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

Motif de bits cyclique d'un code gris

Parfois appelée "binaire réfléchi", la propriété de ne changer qu'un bit à la fois est facilement obtenue avec des modèles de bits cycliques pour chaque colonne à partir du bit le moins significatif:

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

...etc.

Objectif

Avec une chaîne d'entrée non complétée d'un code gris, incrémentez ce dernier en alternant un seul caractère de la séquence ou en ajoutant un préfixe 1(lors de l'incrémentation à la puissance suivante de 2), puis exportez le résultat sous forme de code gris non complété.

Mises en garde

  • Ne vous inquiétez pas de prendre 0ou d'une chaîne vide en entrée.
  • L'entrée la plus basse sera 1, et il n'y a pas de limite supérieure à la longueur de chaîne autre que les limites de mémoire imposées par l'environnement.
  • Par chaîne non complétée, j'entends qu'il n'y aura pas d'espaces de début ou de fin (autres qu'un retour à la ligne facultatif), ni de 0s de début dans l'entrée ou la sortie.

Formats d'E / S

Les formats suivants sont acceptés sous forme d’entrée et de sortie, mais les chaînes sont encouragées par rapport à d’autres formats:

  • le plus significatif "bit" premier
  • tableau de caractères non complété ou chaîne de caractères ASCII '1'et '0's
  • tableau entier non-complété de 1s et 0s
  • tableau booléen non rembourré

Ce qui n'est pas permis:

  • le "bit" le moins significatif en premier
  • entier décimal, binaire ou unaire
  • structure de données de longueur fixe
  • tableau de caractères ou chaîne d'index ASCII non imprimables 1et0

Des tests

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

Plus de tests peuvent être ajoutés sur demande.

Critères

C'est du , donc le programme le plus court en octets gagne! Tous les liens seront brisés en favorisant les soumissions antérieures; les failles standard s'appliquent. La meilleure réponse soumise sera acceptée le 9 octobre 2016 et mise à jour chaque fois que de meilleures réponses seront données.



Pouvons-nous prendre une entrée sous forme de nombre?
xnor

1
Moins évidemment, aussi lié .
Martin Ender

1
Puis-je prendre les deux entrées et sorties inversées, par exemple 0011pour 8
Ton Hospel

1
@TonHospel désolé je n'ai pas vu votre question sur les E / S inversées. Comme je l'ai dit 1000000000, ma réponse est non.
Patrick Roberts

Réponses:


13

Gelée , 10 à 8 octets

Merci à Dennis d'avoir économisé 2 octets.

^\Ḅ‘^H$B

L'entrée et la sortie sont des listes de 0 et de 1.

Essayez-le en ligne!

Explication

L'inverse du code Gray est donné par A006068 . En utilisant cela, il n'est pas nécessaire de générer un grand nombre de codes gris pour rechercher l'entrée. Une classification de cette séquence donnée sur OEIS est la suivante:

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

[]sont les supports de sol. Prenons l'exemple de 44la représentation binaire 101100. Diviser par 2 et les revêtements de sol n’est qu’un virage à droite, coupant le bit le moins significatif. Donc, nous essayons de XOR les nombres suivants

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

Notez que la ncolonne th contient la premièren bits. Par conséquent, cette formule peut être calculée trivialement sur l'entrée binaire en tant que réduction cumulative de XOR sur la liste (qui applique fondamentalement XOR à chaque préfixe de la liste et nous fournit une liste des résultats).

Cela nous donne un moyen simple d’inverser le code Gray. Ensuite, nous incrémentons simplement le résultat et le convertissons en code Gray. Pour la dernière étape, nous utilisons la définition suivante:

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

Heureusement, Jelly semble balancer automatiquement les entrées lorsque vous essayez de les exécuter. Quoi qu'il en soit, voici le code:

^\          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.

Vous n'avez pas besoin Ḟ$; opérateurs au niveau des bits convertis en int .
Dennis

@ Dennis Merci, j'ai découvert cela en écrivant. :)
Martin Ender

@MartinEnder Est-ce que l'entier converti en interne est un grand entier?
Patrick Roberts

@ PatrickRoberts oui, si nécessaire - c'est Python sous le capot.
Jonathan Allan

Belle analyse et explication.
Wayne Conrad

8

JavaScript (ES6), 58 octets

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

Bascule directement le bit approprié. Explication: Comme indiqué dans la réponse de MartinEnder ♦, chaque bit d'un code Gray décodé correspond au XOR cumulé, ou parité, de lui-même et aux bits situés à sa gauche. Nous devons ensuite incrémenter le nombre qui provoque une ondulation de report qui fait basculer tous les 1 bits les plus à droite sur 0, puis les 0 bits suivants sur 1. Le recodage donne un code avec uniquement le 0 position de bit basculé sélectionné. Si la parité de tous les bits 1 est paire, le bit le plus à droite est 0 et nous basculons donc simplement le dernier bit. Si la parité de tous les 1 bits est impair, alors les bits les plus à droite sont 1 et nous devons trouver le dernier bit. C'est maintenant le dernier des bits transportés, le bit que nous devons basculer est le bit suivant de la droite.


Très belle méthode. Est -ce le premier ?à /.?(?=10*$)/vraiment nécessaire? Oh peu importe. Oui, ça l'est. :-)
Arnauld

8

Perl, 27 à 25 octets

Comprend +1 pour -p

Donnez une chaîne d'entrée sur STDIN, par exemple

gray.pl <<< 1010

gray.pl:

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

Perl n'a pas d'entiers bon marché de précision infinie. Vous devez donc basculer directement sur le bit de droite, celui qui se trouve juste avant l'emplacement du dernier chiffre impair 1.


1
Wow, \Grend vraiment les choses faciles pour vous!
Neil

1
D'autre part, \Krend les choses encore plus faciles pour vous.
Neil

Haaaaa ... Maintenant, je veux voir la \Gmise en œuvre aussi.
Urne Magique Octopus

2
@carusocomputing Vous pouvez voir les anciennes versions d'une soumission en cliquant sur le lien modifié
Ton Hospel

6

Haskell, 118 115 108 octets

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

Essayez-le sur Ideone.
Approche naïve: ggénère l’ensemble des codes gris avec longueur n(avec 0-padding), fappels gavec length(input)+1, supprime tous les éléments jusqu’à ce qu’il 0<inputstring>soit trouvé et retourne l’élément suivant (tronquant éventuellement le premier 0).


1
Bonne première réponse! J'espère que nous pourrons bientôt en trouver d'autres plus efficaces.
Patrick Roberts

5

MATL , 18 octets

ZBtE:t2/kZ~tb=fQ)B

Essayez-le en ligne! Ou vérifiez tous les cas de test .

Explication

Soit a ( n ) la séquence d’entiers correspondant aux codes Gray ( OEIS A003188 ). Le programme utilise la caractérisation a ( n ) = n étage XOR ( n / 2), où XOR est exprimé en bits.

Essentiellement, le code convertit l'entrée en un entier égal à 0 , trouve cet entier dans la séquence, puis sélectionne le terme suivant. Cela nécessite la génération d' un nombre suffisant de termes de la suite d' un ( n ). Il s'avère que 2 · un 0 est suffisamment grand. Cela découle du fait que le code Gray un ( n ) n'a jamais plus de chiffres binaires que n .

Prenons l'entrée '101'comme exemple.

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

Je remarque que la sortie est composée de caractères délimités par des espaces ... imprime-t-il une sorte de tableau?
Patrick Roberts

@ PatrickRoberts Oui, exactement. J'ai supposé que c'était acceptable, n'est-ce pas?
Luis Mendo

Je l'accepterai tel quel. J'ai déjà assoupli mes exigences sur le format d'E / S, il est donc inutile de le rendre plus strict à nouveau. Bon travail.
Patrick Roberts

5

CJam (19 octets)

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

Démo en ligne . Il s'agit d'un bloc anonyme (fonction) d'un tableau de bits à un tableau de bits, que la démonstration exécute en boucle.

Cela fonctionne sur le principe simple que si le nombre de bits définis est pair, nous devrions basculer le bit le moins significatif, sinon nous devrions basculer le bit à gauche du bit le moins significatif. En fait, identifier ce bit s'avère beaucoup plus facile en utilisant des hacks de bits sur un entier qu'en utilisant la liste de bits.

Dissection

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

En travaillant uniquement avec le tableau de bits, je pense qu’il est nécessaire de l’inverser: travailler avec le plus à gauche 1est beaucoup plus facile que le plus à droite. Le meilleur que j'ai trouvé jusqu'à présent est (24 octets):

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

Approche alternative (19 octets)

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

Ceci convertit le code Gray en index, incrémente et reconvertit en code Gray.


5

JavaScript (ES6), 53 octets (non en concurrence)

Une fonction récursive qui construit tous les codes de gris jusqu'à ce que l'entrée soit trouvée, puis s'arrête à l'itération suivante.

L'entrée la plus élevée possible dépend de la limite de récursivité du navigateur (environ 13 bits dans Firefox et 15 bits dans 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


Je crains que cette soumission ne soit pas prise en compte, car la méthode ne fonctionne pas pour les longueurs de chaîne illimitées. Veuillez changer en non compétitif si vous voulez garder cette réponse ici.
Patrick Roberts

@ PatrickRoberts - Bien sûr. Ça a du sens.
Arnauld

@ PatrickRoberts Vraiment? Comment une limite de récursivité ne relève-t-elle pas des "limitations de mémoire imposées par l'environnement"?
Sanchises

@sanchises Je faisais allusion à la mémoire heap, mais plus précisément, ce programme se reproduit pour tous les codes gris possibles jusqu'à celui testé, ce qui est extrêmement inefficace. Techniquement, cela pourrait être soumis en tant que "Node.js 6.5" et --harmonyajouté pour les octets de pénalité afin d'avoir accès à l'optimisation de la récursivité des appels différés, ce qui semble possible ici.
Patrick Roberts

@sanchises En regardant ma réponse, c'était un argument médiocre. Le problème principal est que la limitation n'est pas imposée par l'environnement, mais par l'algorithme. Il existe d'autres réponses qui récidivent pour chaque bit plutôt que pour chaque valeur incrémentielle, et je trouve celles-ci plus acceptables, car cela fonctionne pour un éventail de valeurs beaucoup plus large.
Patrick Roberts

2

Retina, 25 octets

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

Je suis convaincu qu'il devrait y avoir une meilleure façon de faire cela ...


Avez-vous réellement besoin de ^?
Ton Hospel

@TonHospel La regex a essayé de s'accorder partout sans cela. (Le mode Remplacer est remplacé par défaut par un remplacement global.)
Neil

2

05AB1E , 12 octets

Utilise le codage CP-1252 .

CÐ<^¹SOÉ*>^b

Essayez-le en ligne!

Explication

Exemple pour l'entrée 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 caractères

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

Python 3, 68 caractères

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

Cette fonction convertit la chaîne binaire donnée en un entier, puis x ou le dernier bit si le nombre de bits définis dans la chaîne d'origine est pair, ou échange le bit situé à gauche du bit défini le plus à droite si le nombre de bits définis dans la chaîne d'origine la chaîne est étrange. Ensuite, il convertit le résultat en chaîne binaire et supprime le 0bpréfixe booléen.


1
Vous pouvez économiser 1 octet en supprimant l'espace après def f(s):et (en supposant Python 2) un autre en utilisant à la printplace de return.
ElPedro

@ElPedro Merci, j'ai aussi appliqué une astuce de condition et pris en compte la taille d'un xor à gauche pour enregistrer quelques caractères supplémentaires :)
Morwenn

Je viens de voir ça.
Bonne

Euh .. en consultant la documentation python, il semble int()générer un entier de 32 bits, bien que mon exigence soit d’incrémenter toute chaîne de longueur. Je ne suis pas sûr que cela soit considéré comme une candidature valide
Patrick Roberts

1
@ PatrickRoberts Je vérifierai plus tard. longau lieu de intpourrait résoudre le problème.
Morwenn

2

C ++, 205 octets

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

Description: Les nombres pairs ont un nombre pair de uns. zCelles variables si zest pair ( z mod 2 = z%2 = 0- autre branche), modifie le dernier bit; Si zest impair, appelez cette fonction sans le dernier caractère et calculez la nouvelle valeur, puis ajoutez le dernier caractère après.

Cliquez ici pour l'essayer pour les cas de test.


Merci pour votre soumission. Si vous pouviez fournir une brève description de votre approche et un lien vers une compilation en ligne de ceci sous forme de démo, je l'apprécierais vraiment.
Patrick Roberts

1
@PatrickRoberts a ajouté le lien et la description que vous avez demandés.
AlexRacer

2

Lot, 199 197 octets

@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%

Lit l'entrée de STDIN dans la variable s. Supprime les 0 et effectue un contrôle de parité sur les 1. S'il y a un nombre impair, il supprime les 0 les plus à droite d'une boucle et s'arrête lorsqu'il supprime un 1. scontient donc le préfixe pair et rle reste de la chaîne.sest mis à zéro s'il était vide afin que son dernier chiffre puisse être basculé, puis tout est concaténé.


1

En fait, 20 19 13 octets

Basé sur la réponse de Martin Ender Jelly avec ma propre version de "réduction cumulative de XOR sur l'entrée". Les suggestions de golf sont les bienvenues. Essayez-le en ligne!

σ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 octets

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

Essayez-le en ligne!

Ceci est essentiellement l'algorithme de Martin dans J.

Notez que 22 b.c'est 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

Bon travail, mec!
Patrick Roberts
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.