Générer une table de recherche à fonction binaire universelle


19

Ceci est tangentiellement lié à ma quête pour inventer un langage de programmation ésotérique .

Un tableau des nombres binaires 0 à 15 peut être utilisé pour implémenter une fonction binaire universelle à l'aide d'opérations d'indexation. Étant donné deux entrées X et Y 1 bit, les 16 fonctions possibles peuvent être encodées dans un opcode 4 bits.

X Y  F|0 1 2 3 4 5 6 7 8 9 A B C D E F
- -    - - - - - - - - - - - - - - - -  
0 0    0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
0 1    0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
1 0    0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
1 1    0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
       -     -   - -   -   -   -   - -
       0    ~X  ~Y ^   &   Y   X   | 1
      ZERO    NOT-Y   AND         OR
          NOT-X   XOR              ONE

Donc, cet ensemble de 16 fonctions peut être appliqué aux entrées binaires comme fonction

U (f, x, y): (f >> ((x << 1) | y)) & 1 ,

ou

U (f, x, y): (f / 2 ^ (x × 2 + y))% 2 ,

ou avec indexation ou partitionnement matriciel.

Il sera utile de connaître la manière la plus compacte de représenter ou de générer une telle table de valeurs pour tout langage possible à construire sur ce type d'opération binaire.

Le but:

Générez cette sortie de texte exacte:

0101010101010101
0011001100110011
0000111100001111
0000000011111111

C'est ça! Le code le plus court gagne.


2
J'avais l'intuition que la famille APL ferait bien ici. :)
luser droog


Les nouvelles lignes de début ou de fin sont-elles acceptées?
Titus

Oui, les nouvelles lignes supplémentaires conviennent.
luser droog

Réponses:


20

J, 10 (13?) Caractères

|.|:#:i.16

Liste des numéros:

   i.16
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15`

en binaire:

   #:i.16
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1

Transposer:

   |:#:i.16
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1

Sens inverse:

   |.|:#:i.16
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1

Faut-il supprimer les espaces? En regardant l'autre réponse J il semble que nous le faisons , nous aurons besoin d'ajouter 3 caractères et emprunter la 1":de la réponse de Jan .


1
Très beau style d'explication. +1 (sacrément court aussi!)
luser droog

Dès que j'ai vu la réponse de Peter's Golfscript, je savais que j'aurais pu faire beaucoup mieux. Eh bien, vous l'aviez déjà fait.
John Dvorak

Ravi de voir quelque chose de plus court que Golfscript ...
fuenfundachtzig


@luserdroog Wow. Ça fait beaucoup de code. Bien plus lisible que le code source J cependant. :-) Très cool.
Gareth

13

Python 2, 40

for n in 1,2,4,8:print 8/n*('0'*n+'1'*n)

7

APL (14)

En supposant ⎕IO=0(c'est un paramètre):

⎕D[⊖(4⍴2)⊤⍳16]

Explication:

  • ⍳16: nombres [0,16)
  • (4⍴2)⊤: encoder chaque numéro de la base 2 en utilisant 4 chiffres
  • : marche arrière horizontale (donc le MSB se retrouve en haut)
  • ⎕D[... ]: sélectionnez ces valeurs à partir ⎕Ddesquelles se trouve la chaîne 0123456789. (Une matrice numérique est affichée avec des espaces entre les valeurs, une matrice de caractères ne l'est pas. Donc, cela convertit chaque bit numérique en l'un des caractères '0' '1').

Le premier caractère de la source est-il censé ressembler à un carré ou manque-t-il encore des polices?
Tim Seguine

@TimSeguine Oui, c'est un carré, appelé quad dans la littérature APL. Les noms de variable commençant par quad sont des variables système qui modifient l'environnement. IO = "origine de l'index".
luser droog

Enregistrer un octet: (4⍴2)⊤2⊥⍣¯1
Adám

6

Gelée , 42 7 octets (non concurrent)

⁴ḶBUz0Y

Essayez-le en ligne!

Merci à Dennis pour son aide. Voici le premier message, voici le dernier (d'autres discussions ont également eu lieu). Avec son aide, j'ai apparemment (presque) enraciné la partition.


Puisque la langue est plus récente que la question, je ne peux pas l'accepter comme réponse. Certainement en lice pour la prime, tho!
luser droog

@luserdroog C'est bien. Mais je pensais que le défi était plus récent.
Erik the Outgolfer le

Je sais ce que tu veux dire, il n'y a pas si longtemps que je l'ai posté. Mais même mon propre inca2, à 2 ans, est une langue trop jeune.
luser droog

+1 pour le 42 à 7 codegolf. C'est quelque chose que vous ne voyez pas tous les jours (sauf si c'est fait exprès).
Kevin Cruijssen

1
@KevinCruijssen Pourquoi cela devrait-il être fait exprès? Je suis juste un débutant Jelly (je connais bien Python 2 et 3), donc je l'ai fait sur une chaîne, alors que je "dois traiter Jelly comme un langage manipulant les tableaux".
Erik the Outgolfer le


4

GolfScript ( 18 17 15 caractères)

(Avec merci à Howard)

16,zip{','-~n}%

Je ne comprends pas pourquoi le 10 caractères

16,zip{n}/

ne fonctionne pas; Je soupçonne qu'un bogue dans l'interpréteur standard entraîne des types non pris en charge sur la pile.

Une alternative à 18 caractères que je comprends bien est:

4,{2\?.2,*$8@/*n}%

Une approche plus mathématique est un peu plus longue, à 28 caractères:

4,{2.@??)2.4??.@/+2base(;n}/

Une grande partie de cela concerne la conversion de base et le remplissage nul. Sans ceux-ci, il tombe à 19 caractères,

4,{2.@??)2.4??\/n}/

avec sortie

21845
13107
3855
255

On lui a demandé une sortie de texte exacte - pourquoi devrait 16,zip{n}/fonctionner alors?
Howard

D'un autre côté, vous pouvez le faire16,zip{','-~n}%
Howard

@Howard, je pense que cela zipdevrait renvoyer un tableau de tableaux, mais il semble en fait renvoyer un tableau de tableaux Ruby (c'est ma meilleure estimation). Quels que soient les éléments, leur appliquer `` `` n'affecte pas la façon dont ils impriment, ce qui ne ressemble à aucun des 4 types de données GolfScript. Vous avez raison qui ','-semble les transformer en tableaux normaux: belle astuce.
Peter Taylor

Semble produire 4 lignes de zéros supplémentaires ici
aditsu

@aditsu, travaille sur la démo en ligne . Je me demande pourquoi la différence. Version rubis, peut-être?
Peter Taylor

3

CJam - 16

4,{G,f{\m>2%}N}/

Code java équivalent (comme explication):

public class Lookup {
    public static void main(final String... args) {
        for (int i = 0; i < 4; ++i) {
            for (int j = 0; j < 16; ++j) {
                System.out.print((j >> i) % 2);
            }
            System.out.println();
        }
    }
}

3

Javascript (ECMA6), 67

s=(k,n)=>n-.5?s((k<<n/2)^k,n/2)+"0".repeat(n)+k.toString(2)+"\n":"" 

Pour l'utiliser, appelez

s(255,8)

Bitshift!
Et aussi XOR et un peu de récursivité.

La première chose à noter est que si nous prenons une ligne et que vous la décalez (# de 0 continus) / 2 à gauche, nous obtenons un joli XOR pour obtenir la ligne suivante.

Par exemple,

0000000011111111 //line 4
0000111111110000 //shifted 4 to the left

XOR ces bits nous donnent

0000111100001111 //XOR'ed. This is line 3!

qui est la ligne suivante (ligne 3).
En appliquant le même processus pour la ligne 3, décalez 2 à gauche et nous obtenons ...

0000111100001111
0011110000111100

XOR'ed donne

0011001100110011

qui est la ligne 2.
Notez que le montant que nous décalons diminue de moitié à chaque fois.
Maintenant, nous appelons simplement cette fonction récursivement, avec 2 arguments. La valeur entière de cette ligne, et N, qui est la quantité que nous devons déplacer. Quand nous faisons récursif juste passer la valeur XOR décalée et n / 2.

"0".repeat(n)

consiste à ajouter des 0 au début de chaque ligne, car toString supprime les 0 au début.


+1 Très cool. Je n'avais pas remarqué ce schéma auparavant.
luser droog

Quelques byes peuvent être supprimés en décalant les bits n au lieu de le diviser et en remplaçant la nouvelle ligne par une chaîne de modèle:s=(k,n)=>n?s((k<<n/2)^k,n>>1)+"0".repeat(n)+k.toString(2)+` `:""
Shaun H

2

J, 21 caractères

1":<.2|(2^i.4)%~/i.16
  • i.16 est une liste de 0..15
  • 2^i.4 est une liste (1,2,4,8)
  • %~/ produit le tableau des divisions où l'argument de gauche forme des lignes mais est l'argument de droite pour la division
  • 2| calcule le reste après avoir divisé [chaque cellule] par deux
  • <. étages dont la valeur est 0 ou 1
  • 1": formate le tableau avec un caractère par cellule

Je pense que cela floorne devrait pas être nécessaire. Le domaine de 2|est déjà 0 ou 1, non?
luser droog

@luserdroog |fonctionne sur des flottants . 2|3.25est 1.25. Nous n'en voulons pas.
John Dvorak

2

GolfScript, 19 caractères

Une autre approche GolfScript

4,{2\?{&!!}+16,%n}%

2

Rubis (44)

Ennuyeux et long: Il suffit d'imprimer les représentations binaires 0-rembourrées des nombres.

[21845,13107,3855,255].map{|i|puts"%016b"%i}

2

Postscript 108 177 126 77 74 70

[43690 52428 61680 65280]
{16{dup 2 mod =only 2 idiv}repeat<>=}forall

Inversée les valeurs d'une simple mo- de méthode.

151 131 119

Appliquer une approche plus APL -ish. edit: remplacement du hachage de chaîne et du zippage du tableau par l'indexation et les boucles for.

[[0 1 15{}for]{16 add 2 5 string cvrs}forall]4 
-1 1{0 1 15{2 index exch get 1 index 1
getinterval =only}for pop<>=}for

Dentelé:

[[0 1 15{}for]{16 add 2 5 string cvrs}forall]
4 -1 1{ % [] i
    0 1 15{ % [] i j
        2 index exch get % [] i [](j)
        1 index 1  % [] i [](j) i 
        getinterval  % [] i [](j)<i>
        =only  % [] i
    }for 
    pop<>= % []
}for

Réimplémenter les fonctions utilisées dans la réponse J gagnante conduit à cela (avec beaucoup de code de support ).

-1 16 i + #: |: |.{{==only}forall()=}forall

ivoici un vecteur basé sur 1 décrit dans les fonctions élémentaires d'Iverson , d'où le -1 ... +produire 0 .. 15.


2

Perl (36 + 1)

+1 pour say, comme d'habitude. le double 0n'est pas une faute de frappe :)

map say((00x$_,1x$_)x(8/$_)),1,2,4,8

Pas besoin d'en ajouter 1 pour say. perl -e'...'est standard et cela nécessite perl -E'...', aucune augmentation du nombre d'octets. Quoi qu'il en soit, je pense qu'il a été décidé , le code de golf Meta qui -M5.01est libre.
msh210

2

JavaScript (ECMA6), 108

Essayer une approche différente ici. Même s'il a été encouragé à utiliser des opérateurs binaires, je me suis permis de soumettre cette solution car le défi est également et je me - comment puis-je réduire la quantité de code représentant ces valeurs ...? Bases .

['gut','a43','2z3','73'].forEach(n=>{a=parseInt(n,36).toString(2);
alert(('00000000'+a).substr(a.length-8))})

(Saut de ligne pour plus de commodité).

C'est dommage que j'ai dû jouer avec le remplissage avec des zéros en tête, mais le point de ce code représente simplement le résultat binaire cible en Base 36, qui sont exactement ces gut, a43, 2z3, 73valeurs.

Remarque: Je me rends compte que ce ne sera pas loin de la réponse gagnante, mais juste pour le plaisir de l'idée ...


1
J'étais sur le point de faire essentiellement la même chose quand j'ai vu le vôtre. Je l' ai jusqu'à 92 octets en utilisant la technique de ma réponse à une question similaire : alert(['gut','a43','2z3',73].map(n=>(1e8+parseInt(n,36).toString(2)).slice(-16)).join('\n')). Cette approche utilise des sauts de ligne au lieu de quatre alert()s.
NinjaBearMonkey


2

MATL ( non concurrent ), 8 octets

16:qYB!P

Essayez-le en ligne!

Explication

16:    % Generate range [1 2 ... 16]
q      % Subtract 1, element-wise
YB     % Convert to binary. Gives a 16×4 char array. Each original number is a row
!      % Transpose
P      % Reverse vertically. Implicitly display

2

CJam ( non concurrent ), 10 9 octets

Merci à @Dennis pour 1 octet de moins!

Y4m*zW%N*

Essayez-le en ligne!

Explication

Y     e# Push 2
4     e# Push 4
m*    e# Cartesian power of 2 (interpreted as [0 1]) with exponent 4
z     e# Zip
W%    e# Reverse the order of rows
N*    e# Join with newlines. Implicitly display

2

JavaScript (ES6), 58 52 octets

Construit la chaîne récursivement.

f=(n=64)=>n--?f(n)+(!n|n&15?'':`
`)+(n>>(n>>4)&1):''

Comment ça fonctionne

Cette récursivité est basée sur le fait que le motif est fait de la représentation binaire verticale des quartets 0x0 à 0xF:

  0101010101010101 bit #0 <- Y = 0
  0011001100110011 bit #1
  0000111100001111 bit #2
  0000000011111111 bit #3 <- Y = 3
  ----------------
  0123456789ABCDEF
  ^              ^
X = 0          X = 15

Par conséquent, chaque position (X, Y) dans ce modèle peut être exprimé comme le Y-ième bit de X: X & (1 << Y). Nous pouvons également isoler ce bit avec: (X >> Y) & 1. Plutôt que de garder une trace de X et Y, nous itérer sur une seule variable nallant de 0 à 63. Ainsi, la formule devient: (n >> (n >> 4)) & 1. Il est en fait plus facile d'itérer de 63 à 0, donc la chaîne est construite dans l'ordre inverse. En d'autres termes, le caractère n-1 est ajouté à gauche du caractère n .

En remarque, la récursivité n'apporte rien ici sauf du code plus court.

Sans les sauts de ligne, le code fait 35 octets:

f=(n=64)=>n--?f(n)+(n>>(n>>4)&1):''

Nous avons besoin de 17 octets supplémentaires pour insérer les sauts de ligne. Cela pourrait être raccourci à 14 octets si un saut de ligne de tête est acceptable.

Démo

f=(n=64)=>n--?f(n)+(!n|n&15?'':`
`)+(n>>(n>>4)&1):''

console.log(f());


Dans l'ideone avec les deux langages JavaScript non compilé dans l'exapme ci-dessus il y en a un de plus .... C'est bien l'idée d'une fonction récursive ...
RosLuP

Que faudrait-il pour séparer après les 35 octets?
Titus

@Titus - Eh bien. À première vue, je n'ai pas de bonne solution pour cela. Voici une (très mauvaise) tentative: (f=(n=64)=>n--?f(n)+(n>>(n>>4)&1):'')().match(/.{16}/g).join`\n` (63 octets)
Arnauld

hmm ... et .replace(/.{16}/g,"$0\n")a la même longueur. Dommage.
Titus


1

NARS2000 APL, 22

"01"[⊖1+(4⍴2)⊤(⍳16)-1]

Dérivé de la réponse APL de marinus, qui ne semble pas fonctionner sur NARS2000.

Générer un vecteur

      ⍳16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Passer à la base zéro

      (⍳16)-1
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Générer une forme pour encoder

      (4⍴2)
2 2 2 2

Encoder

      (4⍴2)⊤(⍳16)-1
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1

Ajuster pour une indexation basée sur 1

      1+(4⍴2)⊤(⍳16)-1
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2
1 1 1 1 2 2 2 2 1 1 1 1 2 2 2 2
1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2
1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2

Inverser l'axe primaire

      ⊖1+(4⍴2)⊤(⍳16)-1
1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2
1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2
1 1 1 1 2 2 2 2 1 1 1 1 2 2 2 2
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2

Indice

      "01"[⊖1+(4⍴2)⊤(⍳16)-1]
0101010101010101
0011001100110011
0000111100001111
0000000011111111

Vous pouvez définir ⎕IO sur 0, afin de ne pas avoir à ajuster pour l'indexation basée sur 1. Cela ramène à 16 caractères.
Elias Mårtenson

Oui, mais je crains qu'elle ne soit trop similaire à l'autre réponse APL et ne mérite pas du tout d'être ici.
luser droog

1

C, 73 caractères

i;main(){for(;i<64;)i&15||puts(""),putchar(48|1&~0xFF0F0F33335555>>i++);}

Il s'agit simplement d'une solution générale pour la sortie de 64 bits dans quatre blocs de 16 bits; il vous suffit de changer le nombre 0xFF0F0F33335555pour sortir une autre séquence de bits.

simplifié & non golfé:

int main() {
    int i;
    for(i = 0; i < 64; i++) {
        if(i % 16 == 0) {
            puts("");
        }
        int bit = ~0xFF0F0F33335555 >> i;
        bit &= 1;
        putchar('0' + bit);
    }
}

1

Haskell, 73

Oui, 73 caractères! Je ne peux pas, pour l'amour de Dieu, réduire cela.

r=replicate
f n=r(div 8n)("01">>=r n)>>=id
main=mapM(putStrLn.f)[1,2,4,8]

Le plus triste à ce sujet est que si vous deviez faire écho à la sortie en utilisant bash, vous n'auriez besoin que de 74 caractères.


1

JavaScript (ES5) 69

for(x="";4>x;x++){z="";for(n=0;16>n;)z+=1-!(n++&1<<x);console.log(z)}


1

inca2 ,33 27 24

4 16#(,`2|(~16)%.2^~4){D

Ceci est basé sur la réponse de Jan Dvorak . inca2 est capable d'exécuter cela à partir des corrections de bugs d'hier. Techniquement invalide puisque la langue a été inventée après la question, mais l' invention d'une langue faisait partie de mon objectif en posant la question. Voici donc un retour sur investissement en remerciement pour les autres réponses. :)

Explication:

4 16#(,`2|(~16)%.2^~4){D
          (~16)               integers 0 .. 15 
                 2^~4         first 4 powers of 2: 1 2 4 8
          (~16)%.2^~4         division table
        2|                    mod 2 (and floor)
       `                      transpose
      ,                       ravel
     (               ){D      map to chars '0'..'9'
4 16#                         reshape to 4x16

Certaines des parenthèses ne devraient pas être nécessaires, mais apparemment, il reste quelques problèmes avec mon interprétation de la grammaire. Et "ravel => map => remodeler" est vraiment maladroit: la carte doit être plus intelligente. Edit: les corrections de bugs permettent l'élimination des parens.


La factorisation de la conversion de base dans une fonction distincte N:x|y%.x^~1+[]/x.ydonne ceci19 Version 16 caractères .

4 16#(,`2N~16){D

Et bien que je triche de toute façon ici, j'ai continué et en ai fait une fonction intégrée. Mais, même s'il s'agit d'une fonction niladique (ne nécessitant pas d'argument), les fonctions niladiques ne sont pas prises en charge et doivent être fournies avec un argument factice.

inca2, 2

U0

1

Pyth 24/26

La méthode la plus courte était la réponse de grc traduite en Pyth que je trouvais bon marché alors j'ai fait ma propre méthode:

Mine: 26 caractères

 mpbjk*/8dS*d[0 1)[1 2 4 8

grc's: 24 caractères

Fd[1 2 4 8)*/8d+*\0d*\1d

1

C ++ 130

Convertit hex en binaire

#define B std::bitset<16>
#define C(x) cout<<x<<endl;
void main(){
B a(0xFF),b(0xF0F),c(0x3333),d(0x5555);
C(d)C(c)C(b)C(a)
}

1

Haskell (Lambdabot), 47 octets

unlines$reverse$transpose$replicateM 4['1','0']

Un peu cheaty car il utilise la transposition de Data.List et replicateM de Control.Monad, cependant les deux sont chargés par défaut depuis Lambdabot.

De plus, je suis sûr qu'il y a place à amélioration, je voulais juste partager l'idée


1

Julia (39 octets)

Deuxième script que j'ai jamais écrit en Julia, je dois admettre que j'aime Julia, c'est une jolie bête.

hcat(map(x->collect(bin(x,4)),0:15)...)

Retour

[0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 
 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 
 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1]  

Explication:

  • bin(x,4) - Convertissez int en entier binaire avec un remplissage à 4 caractères.
  • collect(_) - Fractionner la chaîne en tableau de caractères.
  • map(x->_,0:15) - Procédez ainsi pour les 16 premiers chiffres de la plage.
  • hcat(_...) - Splat et concaténation horizontale dans une matrice.

1

C 83 77 76 74 71

x;f(n){for(;x<4;x++,puts(""))for(n=0;n<16;)putchar(49-!(n++&(1<<x)));}

Assez simple.

x;
f(n){
    for(;x<4;x++,puts(""))
        for(n=0;n<16;)
            putchar(49-!(n++&(1<<x)));
}

1
Il y a une économie facile de 2 en n'utilisant pas ?:, et une autre économie de 1 en déplaçant a ++.
Peter Taylor

Enregistré 3 en changeant mainen f. lol
luser droog

1

R, 53 41 octets

Une traduction de la réponse python de @ grc. Réduit 12 octets de la traduction originale en utilisant des rep()s eachet des lengtharguments (et une correspondance partielle des arguments), et en se souvenant que 0:1c'est équivalent à c(0,1).

for(n in 2^(0:3))print(rep(0:1,e=n,l=16))

for(n in 2^(0:3))print(rep(c(rep(0,n),rep(1,n)),8/n))

Vous pouvez également essayer une traduction de la réponse J de @ Gareth, quelque chose comme ceci (34 octets):

t(e1071::bincombinations(4))[4:1,]

Cependant, il utilise une fonction qui ne fait pas partie de la base R et génère une matrice qui est difficile à formater en texte imprimé exact comme dans la spécification.

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.