Implémenter un additionneur 8 bits


12

Le défi

Implémentez une fonction qui accepte deux entiers dont les valeurs vont de 0 à 255 et renvoie la somme de ces entiers mod 256. Vous ne pouvez utiliser que la négation au niveau du bit (~), au niveau du bit ou (|), des opérateurs de décalage de bit (>>, <<) et affectation (=).

Les choses que vous ne pouvez pas utiliser incluent (mais ne sont pas limitées à)

  • Addition, soustraction, multiplication et division
  • Boucles
  • Expressions conditionnelles
  • Appels de fonction

Les utilisations les moins nombreuses des opérations binaires ou de négation binaire et de décalage de bits l'emportent . En cas d'égalité, la solution la plus populaire l'emporte. Comme toujours, les failles standard s'appliquent.

Voici un exemple d'un simple additionneur 2 bits. Il utilise 77 négations binaires, 28 or binaires et 2 décalages binaires pour un score total de 107 (cela peut être vu en exécutant le préprocesseur C avec gcc -E). Il pourrait être rendu beaucoup plus efficace en supprimant les #defines et en simplifiant les expressions résultantes, mais je les ai laissées pour plus de clarté.

#include <stdio.h>

#define and(a, b) (~((~a)|(~b)))
#define xor(a, b) (and(~a,b) | and(a,~b))

int adder(int a, int b)
{
    int x, carry;
    x = xor(and(a, 1), and(b, 1));
    carry = and(and(a, 1), and(b, 1));
    carry = xor(xor(and(a, 2), and(b, 2)), (carry << 1));
    x = x | carry;
    return x;
}

int main(int argc, char **argv)
{
    int i, j;
    for (i = 0; i < 4; i++) {
        for (j = 0; j < 4; j++) {
            if (adder(i, j) != (i + j) % 4) {
                printf("Failed on %d + %d = %d\n", i, j, adder(i, j));
            }
        }
    }
}

Mise à jour: ajout d'un exemple et modification des critères de notation


2
pourquoi pas au niveau du bit "et"?
rdans

@Ryan La plupart des gens connaissent mieux les portes NAND que les portes NOR :)
Orby

1
la récursivité compte-t-elle comme une boucle?
rdans

@Ryan Recursion compte comme une boucle, bien que je ne sais pas comment vous l'implémenteriez sans instruction conditionnelle.
Orby

Le débordement est-il défini ou puis-je simplement sortir quoi que ce soit s'il déborde?
Comintern

Réponses:


8

Python, 36 opérations

Une méthode logarithmique dans le paramètre "8"!

def add(a,b):
    H = a&b   #4 for AND
    L = a|b   #1 
    NX = H | (~L) #2
    K = NX 

    H = H | ~(K | ~(H<<1)) #5
    K = K | (K<<1) #2

    H = H | ~(K | ~(H<<2)) #5
    K = K | (K<<2) #2

    H = H | ~(K | ~(H<<4)) #5

    carry = H<<1 #1

    neg_res = NX ^ carry  #7 for XOR
    res_mod_256 = ~(neg_res|-256) #2
    return res_mod_256

L'idée est de savoir quels indices débordent et quelle cause porte. Au départ, ce sont juste les endroits où les deux aandd bont un 1. Mais étant donné que les bits transportés peuvent provoquer des chevauchements supplémentaires, cela doit être déterminé de manière itérative.

Plutôt que de déborder chaque index dans le suivant, nous accélérons le processus en déplaçant 1 index, puis 2 indices, puis 4 indices, en étant sûr de se souvenir des endroits où un débordement s'est produit (H) et où un débordement ne peut plus se produire (K ).


Une solution itérative plus simple avec 47 opérations:

def add(a,b):
    H = a&b   #4 for AND
    L = a|b   #1 
    NX = H | (~L) #2

    c=H<<1  #1

    for _ in range(6): #6*5
        d = (~c)|NX
        e = ~d
        c = c|(e<<1)

    res = c ^ NX  #7 for XOR

    res_mod_256 = ~(res|-256) #2
    return res_mod_256

Banc d'essai, pour quiconque souhaite le copier.

errors=[]
for a in range(256):
    for b in range(256):
        res = add(a,b)
        if res!=(a+b)%256: errors+=[(a,b,res)]

print(len(errors),errors[:10])

9

C - 0

Il utilise des opérateurs en dehors de ~, |, >>, << et =, mais je vois des solutions utilisant des opérateurs de transtypage et de virgule, donc je suppose que la règle n'est pas trop stricte à condition qu'elle n'utilise pas les opérateurs interdits.

unsigned char sum(unsigned char x, unsigned char y)
{
    static unsigned char z[] = {
        0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
        16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
        32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
        48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
        64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
        80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
        96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
        112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
        128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
        144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
        160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
        176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
        192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
        208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
        224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
        240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
        0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
        16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
        32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
        48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
        64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
        80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
        96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
        112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
        128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
        144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
        160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
        176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
        192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
        208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
        224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
        240,241,242,243,244,245,246,247,248,249,250,251,252,253,254
    };

    return (&z[x])[y];
}

C'est évidemment une faille, mais +1 pour le signaler.
Orby

7

python, score = 83 80

def g(x,y):
    for i in xrange(7):
        nx = ~x
        ny = ~y
        x,y = ~(x|ny)|~(nx|y), (~(nx|ny))<<1
    x = ~(x|~y)|~(~x|y)
    return ~(~x|256)

Déroulez la boucle. C'est 10 opérations par boucle fois 7 boucles, 7 pour le dernier xor et 3 pour écraser le 9e bit à la fin.

Implémente l'équation x+y = x^y + 2*(x&y)en la répétant 8 fois. Chaque fois, il y a un bit zéro de plus en bas de y.


7

C, score: 77 60

Golfé juste pour l'enfer, 206 169 131 octets:

#define F c=((~(~c|~m))|n)<<1;
a(x,y){int m=(~(x|~y))|~(~x|y),n=~(~x|~y),c;F F F F F F F return (unsigned char)(~(m|~c))|~(~m|c);}

Étendu:

int add(x,y)
{
    int m=(~(x|~y))|~(~x|y);
    int n=~(~x|~y);
    int c = 0;
    c=((~(~c|~m))|n)<<1; 
    c=((~(~c|~m))|n)<<1; 
    c=((~(~c|~m))|n)<<1; 
    c=((~(~c|~m))|n)<<1; 
    c=((~(~c|~m))|n)<<1;    
    c=((~(~c|~m))|n)<<1; 
    c=((~(~c|~m))|n)<<1; 
    return (int)((unsigned char)(~(m|~c))|~(~m|c));
}

Essentiellement la même solution (mathématiquement) que @KeithRandall @JuanICarrano a proposée , mais tire parti de la capacité de C à jouer rapidement et librement avec des types variables et des pointeurs pour tout effacer après les 8 premiers bits sans utiliser plus d'opérateurs.

Dépend de l'endian-ness de la machine et de la taille de () un int et un char, mais devrait pouvoir être porté sur la plupart des applications spécifiques à la machine avec le calcul de pointeur approprié.

EDIT: C'est un défi que C (ou d'autres langages de bas niveau) aura un avantage distinct - à moins que quelqu'un ne propose un algorithme qui n'a pas à porter.


Si vous allez gérer le film de cette façon, vous pouvez simplement lancer le casting unsigned char. C'est plus propre et plus portable.
Orby

@Orby - Je suppose que taper unsignedne me vient pas naturellement dans le golf de code. Vous avez bien sûr raison - mis à jour.
Komintern

4

Python - Score 66 64

def xand(a,b):
    return ~(~a|~b) #4

def xxor(a,b):
    return (~(a|~b))|~(~a|b) #7

def s(a,b):
    axb = xxor(a,b)   #7
    ayb = xand(a,b)   #4

    C = 0
    for i in range(1,8):
        C = ((xand(C,axb))|ayb)<<1    #(1+1+4)x7=6x7=42

    return xxor(axb,xand(C,255))    #7 + 4 = 11
    #total: 7+4+42+11 = 64

C'est l'équation pour un additionneur ondulé. C est le portage. Il est calculé un bit à la fois: à chaque itération le report se propage à gauche. Comme l'a souligné @Orby, la version originale n'a pas fait d'ajout modulaire. Je l'ai corrigé et j'ai également enregistré un cycle dans l'itération, car le premier report est toujours nul.


3
Beau travail, mais votre code ne s'enroule pas correctement (c'est-à-dire s(255,2)retourne 257plutôt que 1). Vous pouvez corriger cela en modifiant votre dernière ligne, return ~(~xxor(axb,C)|256) ce qui ajoute 3 points.
Orby

2

C ++ - score: 113

#define ands(x, y) ~(~x | ~y) << 1
#define xorm(x, y) ~(y | ~(x | y)) | ~(x | ~(x | y))

int add(int x, int y)
{
int x1 = xorm(x, y);
int y1 = ands(x, y);

int x2 = xorm(x1, y1);
int y2 = ands(x1, y1);

int x3 = xorm(x2, y2);
int y3 = ands(x2, y2);

int x4 = xorm(x3, y3);
int y4 = ands(x3, y3);

int x5 = xorm(x4, y4);
int y5 = ands(x4, y4);

int x6 = xorm(x5, y5);
int y6 = ands(x5, y5);

int x7 = xorm(x6, y6);
int y7 = ands(x6, y6);

int x8 = xorm(x7, y7);
int y8 = ands(x7, y7);

return (x8 | y8) % 256;
}

add(1, 255)retourne 128 pour moi, @Ryan.
Orby

@Orby est résolu maintenant
rdans

%ne figure pas sur la liste des opérateurs autorisés, à savoir ~, |, >>, et <<. Peut-être le remplacer par ands(x8|y8, 255)>>1?
Orby

En fait, ~(~x8 | y8 | 0xFFFFFF00)ferait bien l'affaire avec seulement 4+ pour votre score.
Orby

2
Mais ne pas faire le type byteau lieu de le intferait-il déborder automatiquement?
fier haskeller
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.