Faisons un peu d'arithmétique de localisation!

22

De l'article Wikipedia :

L'arithmétique de localisation (Latin arithmeticæ localis) est les systèmes numériques binaires additifs (non positionnels) que John Napier a explorés comme technique de calcul dans son traité Rabdology (1617), à la fois symboliquement et sur une grille de type échiquier.

Quelle?

Les chiffres d'emplacement sont un moyen d'écrire des nombres en utilisant les lettres de l'alphabet.

La notation binaire n'avait pas encore été normalisée, donc Napier a utilisé ce qu'il a appelé des chiffres d'emplacement pour représenter des nombres binaires. Le système de Napier utilise la notation de valeur de signe pour représenter les nombres; il utilise des lettres successives de l'alphabet anglais pour représenter des puissances successives de deux: a = 2 ^ 0 = 1, b = 2 ^ 1 = 2, c = 2 ^ 2 = 4, d = 2 ^ 3 = 8, e = 2 ^ 4 = 16 et ainsi de suite.

Un exemple

ab = 1 + 2 = 3 en base 10

aabb = 1 + 1 + 2 + 2 = 6 en base 10

Notez que cela aabbpeut être raccourci bcen remplaçant 2 instances d'une lettre par une plus élevée.

Une addition

Vous venez de concaténer les deux nombres et de simplifier.

acd+ bde= acdbde= abcdde= acebe= abcf= 39en base 10

Soustraction

Supprimez simplement tous les chiffres apparaissant également dans les deux parties de la soustraction. Une extension (conversion ben aa) peut être nécessaire

abde- ad= be= 18 en base 10

Multiplication

C'est un peu plus difficile.

Disons que nous voulons multiplier acd(13) par def(56). Vous organisez d'abord acdverticalement:

a
c
d

Ensuite, vous ajoutez defaprès le premier a:

a def
c
d

Maintenant, c est 2 positions plus tard dans l'alphabet que a, donc nous ajoutons 2 positions dans l'alphabet defà faire fgh. Cela est ajouté à la deuxième ligne.

a def
c fgh
d

Enfin, d est 1 position plus tard dans l'alphabet que c, nous ajoutons donc 1 position dans l'alphabet fghà faire ghi. Cela est ajouté à la troisième ligne.

a def
c fgh
d ghi

Ensuite, vous prenez la somme de la droite: def+ fgh+ ghi= deffgghhi= deggghhi= deghhhi= deghii= deghj(728)

Un autre exemple de multiplication

Contribution:

bc * de

Première:

b
c

ensuite

b ef
c 

ensuite

b ef
c fg

Notez que nous avons écrit efsur la première ligne. C'est parce que bccommence par b, et best la deuxième lettre de l'alphabet, nous devons donc décaler ded'une lettre, donc cela devient ef.

ensuite

ef+fg

Sortie:

eh

Division

Cela ne fait pas partie de ce défi, car cela peut devenir très complexe.

Votre véritable défi

Votre programme ou fonction doit prendre l'entrée comme une chaîne qui ressemble à ceci:

a + b

Et vous devez sortir:

ab

Bien sûr, votre programme ou la fonction doit prendre en charge un nombre de longueur arbitraire (jusqu'à la chaîne ou de limiter l' entrée de votre langue) avec l' un des opérateurs +, -ou *. Quelques exemples supplémentaires:

Contribution:

ab + bd

Sortie:

acd

Contribution:

d - ab

Sortie:

ac

Contribution:

ab * cd

Sortie:

cf

Remarques:

  • L'ordre des lettres dans la sortie n'a pas d'importance, mais vous pouvez toujours supposer que l'ordre des lettres en chiffres dans l'entrée sera croissant (a avant z).
  • Vous pouvez prendre une entrée avec une nouvelle ligne de fin et une sortie avec une nouvelle ligne de fin.
  • Vous ne pouvez pas prendre la saisie comme une liste de ab, *et bdpour ab * bd.
  • L'alphabet anglais est utilisé ( abcdefghijklmnopqrstuvwxyz)
  • Votre sortie doit être simplifiée ( aan'est pas autorisée, best obligatoire)
  • L'entrée sera simplifiée ( b+ c, pas aa+ bbou aa+ aaaa)
  • Vous pouvez avoir besoin d' un espace avant et l'opérateur ( +, -ou *), ou vous pouvez exiger qu'il y ait aucune.
  • Il n'y aura qu'un seul opérateur par entrée.
  • Vous pouvez supposer que la sortie et l'entrée ne dépasseront jamais 2 ^ 27-1 ( abcdefghijklmnopqrstuvwxyz)
  • C'est le , donc la réponse la plus courte en octets l'emporte!
programmer5000
la source
2
d is 2 positions later in the alphabet than cest ce Wright? ne devrait-il pas en être ainsi 1? That is added to the second row.sur la même phrase, n'est-ce pas third?
Felipe Nardi Batista du
1
@FelipeNardiBatista l'alphabet anglais est utilisé ici, édité cela.
programmer5000
@ programmer5000 toujours, bc*de==efghmais ce efghn'est 240pas le cas144
Felipe Nardi Batista
1
bc*dedevrait êtreeh
Felipe Nardi Batista
@Dada, il n'y aura qu'un seul opérateur par entrée.
programmer5000

Réponses:

3

Gelée , 26 25 octets

i@€Øað’2*S;ḟ.Ḣ
ḲÇ€VBṚTịØa

Utilise les opérateurs de Jelly ( ×plutôt que *et _plutôt que -) dans la chaîne d'entrée comme le permet l'OP .

(Nécessite des espaces autour des opérateurs)

Essayez-le en ligne! ou voir la suite de tests

Comment?

i@€Øað’2*S;ḟ.Ḣ - Link 1, transform from input sub-string to value or operator: sub-string
i@€            - 1st index of, for €ach (or 0 if not found) [reversed @rguments] in:
   Øa          -      lowercase alphabet (i.e. a->1, b->2, ..., non-alpha->0)
     ð         - dyadic chain separation i.e. f(result above, substring):
      ’        - decrement (i.e a->0, b->1, ..., non-alpha->-1)
       2*      - 2 raised to that power
         S     - sum
          ;    - concatenate with the substring
           ḟ   - filter out:
            .  -     0.5 (for an operator substring the evaluated 0.5 is removed)
             Ḣ - head (i.e. the evaluation for a location, and the operator otherwise)

ḲÇ€VBṚTịØa - Main link: string                        e.g. 'ab × cd'
Ḳ          - split on spaces                               [['a','b'],['×'],['c','d']]
 Ç€        - last link (1) as a monadic function for €ach  [3,'×',12]
   V       - evaluate as Jelly code                        36
    B      - convert to binary                             [1,0,0,1,0,0]
     Ṛ     - reverse                                       [0,0,1,0,0,1]
      T    - truthy indexes                                [3,6]
       ị   - index into:
        Øa -     lowercase alphabet                        ['c','f'] (i.e. "cf", which is implicitly printed when run as a full program)
Jonathan Allan
la source
7

Mathematica, 168 octets

FixedPoint[StringReplace[x_~~x_:>FromCharacterCode[c@x+1]],Table["a",ToExpression@StringReplace[#,x:LetterCharacter..:>ToString@Tr[2^((c=ToCharacterCode)@x-97)]]]<>""]&

Ma solution initiale (avant la publication du post pour préciser que la sortie devait être simplifiée) était 64plus courte en octets:

Table["a",ToExpression@StringReplace[#,x:LetterCharacter..:>ToString@Tr[2^(ToCharacterCode@x-97)]]]<>""

Cela vient de modifier cette solution pour qu'elle fonctionne. Il est probablement plus court d'utiliser les méthodes décrites dans le défi, mais je voulais quand même mettre cela en place.

Explication:

Remplace chaque séquence de lettres par son entier correspondant par une arithmétique de code de caractères, puis convertit la chaîne résultante en une expression (qui se simplifiera automatiquement en un entier), puis produit une chaîne de acaractères de longueur égale à cet entier, et remplace finalement les adjacents identiques caractères avec le code de caractère suivant jusqu'à ce qu'un point fixe soit atteint.

ngenisis
la source
2
Oh, il n'y a pas de code intégré à 1 caractère? Surprenant!
programmer5000
7

JavaScript (ES6), 136 134 133 octets

1 octet enregistré grâce à Luke

s=>[...a='abcdefghijklmnopqrstuvwxyz'].filter((c,i)=>eval(s.replace(/\w+/g,s=>[...s].reduce((p,c)=>p|1<<a.search(c),0)))&1<<i).join``

Cas de test

Arnauld
la source
Bien fait! Tu m'as battu ...
programmer5000
Est-ce que cela se transforme en décimal et inversement? Il en est ainsi.
programmer5000
1
@ programmer5000 Oui en effet. Je soupçonne que de nombreuses réponses le seront. (Sauf bien sûr Mathematica, qui a probablement une fonction intégrée pour cela. ^^)
Arnauld
Il semble que votre commentaire ne contienne pas de lien. Qu'est-ce qu'un fot intégré?
programmer5000
@ programmer5000 (En fait, il manquait un mot.)
Arnauld
5

Perl 5 , 95 octets

94 octets de code + -pindicateur.

s/\w/a x 2**(-97+ord$&)/ge;s/(.*)-\1|\+//;/\*/&&($_=$`x length$');1while s/(.)\1/chr 1+ord$1/e

Essayez-le en ligne!

Trois étapes ici:
- s/\w/a x 2**(-97+ord$&)/ge;convertit l'entrée en une chaîne de aseulement.
- s/(.*)-\1|+//;/*/&&($_=$`x length$')exécutera l'opérateur (qui est très simple sur les chaînes de a): +est la concaténation, -signifie supprimer de la première partie autant aqu'il y en a dans la deuxième partie, et *signifie dupliquer la première partie autant de fois qu'il y en a adans la seconde partie.
- 1while s/(.)\1/chr 1+ord$1/ereplie les mêmes lettres consécutives dans la lettre suivante de l'alphabet.

Dada
la source
La seule réponse qui ne se convertit pas en décimal! Bon travail!
programmer5000
1
@ programmer5000 Sur 2 réponses, je n'appellerais pas ça impressionnant!
Dada
5

05AB1E , 29 octets

ð¡À¬U¦v0yvAyko+}}X.VbRvyiANèJ

Essayez-le en ligne! ou comme suite de tests

Explication

ð¡                             # split input on string
  À                            # rotate left
   ¬U¦                         # get the operator, store it in X and remove it from list
      v                        # for each side of the equation
       0                       # push 0 as an accumulator
        yv                     # for each letter in each side of the equation
          Ayk                  # get its index in the alphabet
             o                 # raise 2 to this power
              +                # add to the accumulator
               }}              # end loops
                 X.V           # apply the operator to the 2 numbers now on the stack
                    bR         # convert to binary and reverse
                      v        # for each binary digit
                       yi      # if it is true
                         ANè   # get the letter at that index in the alphabet
                            J  # join stack to a single string
Emigna
la source
5

C & x86 asm, 340 octets

Compiler avec -O0

#define G getchar()
g(){int c,a=0;for(;islower(c=G);)a+=1<<(c-97);return a;}
main(){short o[]={[43]=0x4403,[45]=0x442b,[42]=0x6cf7};
mprotect((long)&&l&~4095,4096,7);
for(;;){int c,b=0,a=g();*(short*)&&l=o[G];G;g();asm("xchg %%eax,%0":"+m"(a));
l:asm("addl %1,%%eax":"=a"(c):"m"(a));
for(;a=c>>b;b++)if(a&=1)putchar(97+b);putchar(10);}}

Explication

Comme C n'en a pas eval(), j'ai utilisé un tableau d'instructions x86 à sa place. J'ai dû choisir des instructions qui étaient toutes de la même longueur (ou rembourrées avec des nops), et qui attendaient src et destination des mêmes types. Il était particulièrement gênant que MUL ne puisse écrire que sur des registres et que les opcodes MUL à 1 octet ne pouvaient écrire que sur EAX. De plus, il ne semblait pas y avoir d'instruction SUB d'écriture de registre soustraite de la mémoire, au lieu de l'inverse, d'où le XCHG.

modifier

Comme cela a été demandé dans les commentaires, une approche plus traditionnelle ressemblerait à ceci:

#define G getchar()
#define return r
#define int i
g(){i c,a=0;for(;islower(c=G);)a+=1<<(c-97);r a;}
a(i x,i y){r x+y;}s(i x,i y){r x-y;}m(i x,i y){r x*y;}
main(){i(*o[])(i,i)={[43]=a,[45]=s,[42]=m};
for(;;){i c,b,a=g();b=G;G;g();c=o[b](a,g());
for(b=0;a=c>>b;b++)if(a&=1)putchar(97+b);putchar(10);}}

Il est en fait un peu plus court, à 301 caractères, pour plusieurs raisons: 1. Parce qu'il doit y avoir beaucoup de fonctions, la surcharge de chacune peut être hachée avec quelques règles de préprocesseur. 2. Linux moderne protège de l'exécution sur la pile, donc l'appel mprotect () pour désactiver ces 34 octets sacrifiés. 3. L'appel XCHG est très sous-optimal et coûte 30 octets supplémentaires. Sinon, le combo x86 gagnerait d'environ 10 à 20 octets.

Également haché 2 octets des deux en améliorant l'appel islower () en g.

Dave
la source
Je ne peux pas vraiment dire comment cela se comparerait à une approche plus classique en termes de taille de code, mais j'aime vraiment votre solution. +1
Arnauld
5

GNU sed + coreutils, 329 octets

Ouais, je n'ai aucune idée de ce qui m'a pris, mais au moins je connais un peu mieux les scripts sed maintenant. Notez que cette solution nécessite l' eextension GNU sed , qui exécute une commande shell.

/\+/{s/\+//
b S}
/-/{:E
/a+-a+/{s/(a*)(a*)-\2/\1/
b S}
s/.*/echo &|tr b-z- A-Y-/
e
s/([A-Z])/\L\1\1/g
b E}
/\*/{h
:M
/^\*/{x
s/[^\n]*//
s/\n//g
b S}
s/(.).*\*(.*)/echo \2|tr a-z \1-za-z/
e
H
g
s/.(.*)/\1/
h
s/\n.*//
b M}
:S
s/^.*$/echo &|grep -o .|sort|tr -d '\n'/
e
:L
s/(.)\1/\u\1/g
/^[a-z]*$/ q
s/.*/echo &|tr A-Z b-za/;e
b L

Je suppose qu'il n'y aura pas d'espace autour des opérateurs. Depuis mon terminal:

$ sed -rf golf.sed <<< a+b
ab
$ sed -rf golf.sed <<< ab+bd
acd
$ sed -rf golf.sed <<< abc+b
ad
$ sed -rf golf.sed <<< d-ab
ca
$ sed -rf golf.sed <<< ab*cd
cf
$ sed -rf golf.sed <<< bc*de
eh
$ sed -rf golf.sed <<< acd*def
deghj

Et, pour les plus sains que moi: la version commentée!

#!/bin/sed -rf

/\+/ {
    s/\+//
    b simplify
}

/-/ {
    # expand pattern space; everything will now be 'a's
    :E
    /a+-a+/{
        # Remove doubled 'a's on either side of the dash. For example,
        # for input d-ab, space is now 'aaaa-aaa'; substitute this to 'a'
        s/(a*)(a*)-\2/\1/
        b simplify
    }
    # shift letters that aren't 'a' down and double them
    s/.*/echo &|tr b-z- A-Y-/;e
    s/([A-Z])/\L\1\1/g
    b E
}

/\*/ {
    # Hold space: line 1 is pattern, other lines are output
    h
    :M

    # if space starts with *, we've eaten entire arg0; sum and simplify
    /^\*/ {
        x
        s/[^\n]*//      # remove first line, which is our pattern
        s/\n//g         # remove newlines to add results together
        b simplify
    }

    # convert pattern into shifting command
    s/(.).*\*(.*)/echo \2|tr a-z \1-za-z/

    # execute it, append result to hold space
    e
    H

    # restore pattern, with leading char and all output lines removed
    g
    s/.(.*)/\1/
    h
    s/\n.*//

    b M
}

:simplify
# reorder all letters so all 'a's are before all 'b's are before all 'c's
# are before ... etc    
# See /programming/2373874
s/^.*$/echo &|grep -o .|sort|tr -d '\n'/
e

:L
# Replace repeated characters with themselves upper-cased, then translate
# upper-cased characters to what they should be.
s/(.)\1/\u\1/g
/^[a-z]*$/ q
s/.*/echo &|tr A-Z b-za/;e
b L
charliegreen
la source
+1 pour le code sed et bienvenue sur PPCG! La convention ici quand on ne résout pas en pure GNU sed (ou dans tout autre langage pur), est d'ajouter au titre les commandes système utilisées, comme "GNU sed + coreutils" par exemple, même si vous mentionnez appeler une commande shell dans la description . Ceci est fait pour différencier, en particulier dans les défis avec les classements, des réponses GNU sed pures.
seshoumara
De plus, à l'exception du drapeau «f» nécessaire à chaque fois, tout autre drapeau doit être compté comme 1 octet. Votre score est donc de 329. Vous voudrez peut-être le mentionner dans la description. Et pour terminer, vous pourriez penser à ajouter un lien vers un interprète sed en ligne, comme TIO .
seshoumara
Pour ne pas parler et ne rien faire, voici un 43 octets plus court! version de votre code (286 octets dont -r), que j'ai trouvée en jouant aux commandes. Je suis sûr que cela peut être encore plus court.
seshoumara
Ah, d'accord, bon à savoir! Aussi, bon golf! Quelle version de sed utilisez-vous cependant? Le vôtre fonctionne dans TIO, mais dans GNU sed 4.4 je viens de recevoirsed: file golf.sed line 24: ":" lacks a label
charliegreen
L'étiquette sans nom est un bogue bien connu dans GNU sed, qui a été corrigé dans la version 4.3. Mais sur PPCG, vous pouvez écrire des programmes pour n'importe quelle variante et version sed, en utilisant des bugs comme fonctionnalités si cela aide au golf. Les différences entre les versions sont trop petites pour être mentionnées (4.2 vs 4.4), mais la variante (standard POSIX sed vs GNU sed étendu) doit être spécifiée dans le titre, avec la mention des programmes système appelés, le cas échéant.
seshoumara
4

PHP, 168

Sortie croissante avec utilisation de eval

[$a,$o,$b]=explode(" ",$argn);function d($s){for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);return$n;}for(eval("\$k=d($a)$o d($b);");$i<26;)echo$k&2**$i++?chr(96+$i):"";

PHP, 185 octets

Sortie croissante

[$a,$o,$b]=explode(" ",$argn);function d($s){for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);return$n;}for(;$i<26;)echo(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b))&2**$i++?chr(96+$i):"";

Version en ligne

Étendu

[$a,$o,$b]=explode(" ",$argn); # part the input into variables
function d($s){ # make decimal value
    for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);
    return$n;
}
for(;$i<26;)
echo(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b))&2**$i++?chr(96+$i):""; # Bitwise Compare and Output

PHP, 201 octets

Sortie décroissante

[$a,$o,$b]=explode(" ",$argn);function d($s){for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);return$n;}for($r=(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b));$r;$r-=2**$l)$t.=chr(97+$l=log($r,2)^0);echo$t;

Version en ligne

Étendu

[$a,$o,$b]=explode(" ",$argn); # part the input into variables
function d($s){ # make decimal value
    for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);
    return$n;
}
for(
$r=(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b)) # result of the operation
;$r;
$r-=2**$l) # subtract the letter value 
$t.=chr(97+$l=log($r,2)^0); # find greatest letter
echo$t; # Output
Jörg Hülsermann
la source
4

Python 3 , 176 167 octets

i=lambda a:str(sum(1<<ord(i)-97for i in a))
def f(a):
 a,b,c=a.split();m=eval(i(a)+b+i(c));r=''
 while m:
  t=0
  while m>=2**t*2:t+=1
  r+=chr(97+t);m-=2**t
 return r

Essayez-le en ligne!

  • enregistré 9 octets: Merci à tutleman
officialaimm
la source
1
À moins que je ne me trompe pas , vous pouvez raser deux octets en remplaçant m>=2**(t+1)avec m>=2**t*2, et cinq octets en remplaçant a=a.split();m=eval(i(a[0])+a[1]+i(a[2]))par quelque chose comme b,c,d=a.split();m=eval(i(b)+c+i(d)).
Tutleman
1
Oh, et deux octets de plus en remplaçant 2**(ord(i)-97)par 1<<ord(i)-97.
Tutleman
1
Je suis étonné de la lisibilité de cette solution par rapport à d'autres solutions.
Ole Tange
Je vous remercie :). Mais je pense que c'est aussi parce que le python est le langage utilisé. L'indentation fait augmenter le nombre d'octets, cependant lisible. ;)
officialaimm
2

PHP, 130

for($d=a;$e=$argn[$i++];)$e!=' '?$d!=b?$$d+=1<<ord($e)-97:$b=$e:++$d;eval("for(;\$j++<27;)echo($a$b$c>>\$j-1)&1?chr(96+\$j):'';");

version étendue:

for($d=a;$e=$argn[$i++];)       // for each char in the input
  $e!=' '?                      //   if space
    $d!=b?                      //     if not the operation
      $$d+=1<<ord($e)-97:       //       add 2^(char - 'a')
      $b=$e:                    //     else save operation
    ++$d;                       //   else increase "pointer"
eval("for(;\$j++<27;)           // for each bit in the output
        echo($a$b$c>>\$j-1)&1?  //   calulate the result and check the bit
          chr(96+\$j):          //     output corrosponding char
          '';                   //     output nothing
     ");

courir avec php -R <code>.

Christoph
la source
1

AWK, 201 octets

BEGIN{RS="(.)"}n=index(V="abcdefghijklmnopqrstuvwxyz",RT){s+=2^--n}index("+-*",RT){a=s RT
s=0}END{RS="\n"
"(awk '$0="a s"'<<<1)"|getline v
for(j=26;j--;)if((s=v-2^j)>=0){v=s;c=substr(V,j+1,1)c}print c}

"(awk '$0="a s"'<<<1)"|getline vest la meilleure façon que je pouvais venir avec faire un evaluatedans AWK. Je «triche» peut-être un peu pour appeler cela simplement AWK, puisque j'exécute une commande, mais au moins la commande est aussi AWK:)

Je suis sûr que je manque un moyen de réduire le nombre d'octets, mais je ne le vois certainement pas.

L' utilisation est assez standard, par exemple , mettre le code FILEet faire:

awk -f FILE <<< "bc + ab"

Notez que les espaces ne sont pas requis et tout caractère non op / non [az] sera silencieusement ignoré. Pourrait être étendu pour fonctionner avec des nombres supérieurs à "abcdefghijklmnopqrstuvwxyz" en modifiant la boucle. Pour faire la division, ajoutez simplement le /caractère à la chaîne d'opération :). Imprime également une ligne vierge si le result <= 0.

Robert Benson
la source