Facciamo un po 'di aritmetica della posizione!


22

Dalla voce di Wikipedia :

L'aritmetica della posizione (latino arithmeticæ localis) è il sistema numerico binario additivo (non posizionale), che John Napier esplorò come tecnica di calcolo nel suo trattato Rabdology (1617), sia simbolicamente che su una griglia simile a una scacchiera.

Che cosa?

I numeri di posizione sono un modo di scrivere numeri usando le lettere dell'alfabeto.

La notazione binaria non era ancora stata standardizzata, quindi Napier usò quelli che chiamava numeri di posizione per rappresentare numeri binari. Il sistema di Napier utilizza la notazione valore-segno per rappresentare i numeri; utilizza lettere successive dell'alfabeto inglese per rappresentare potenze successive di due: a = 2 ^ 0 = 1, b = 2 ^ 1 = 2, c = 2 ^ 2 = 4, d = 2 ^ 3 = 8, e = 2 ^ 4 = 16 e così via.

Un esempio

ab = 1 + 2 = 3 nella base 10

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

Si noti che aabbpuò essere abbreviato bcsostituendo qualsiasi 2 istanze di una lettera con una più alta.

aggiunta

Basta concatenare i due numeri e semplificare.

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

Sottrazione

Basta rimuovere tutte le cifre che appaiono allo stesso modo in entrambe le parti della sottrazione. Potrebbe essere necessario espandere (convertire bin aa)

abde- ad= be= 18 in base 10

Moltiplicazione

Questo è un po 'più difficile.

Diciamo che vogliamo moltiplicare acd(13) per def(56). Per prima cosa disponi in acdverticale:

a
c
d

Quindi aggiungi defdopo il primo a:

a def
c
d

Ora, c è 2 posizioni più avanti nell'alfabeto rispetto a a, quindi aggiungiamo 2 posizioni nell'alfabeto defda fare fgh. Viene aggiunto alla seconda riga.

a def
c fgh
d

Infine, d è 1 posizione più avanti nell'alfabeto rispetto a c, quindi aggiungiamo 1 posizione nell'alfabeto fghda creare ghi. Viene aggiunto alla terza riga.

a def
c fgh
d ghi

Quindi prendi la somma del diritto: def+ fgh+ ghi= deffgghhi= deggghhi= deghhhi= deghii= deghj(728)

Un altro esempio di moltiplicazione

Ingresso:

bc * de

Primo:

b
c

Poi

b ef
c 

Poi

b ef
c fg

Si noti che abbiamo scritto efsulla prima riga. Questo perché bcinizia con b, ed bè la seconda lettera dell'alfabeto, quindi dobbiamo spostare dedi 1 lettera, così diventa ef.

Poi

ef+fg

Produzione:

eh

Divisione

Questo non fa parte di questa sfida, perché può diventare molto complessa.

La tua vera sfida

Il tuo programma o funzione deve accettare input come una stringa simile al seguente:

a + b

E devi produrre:

ab

Naturalmente, il vostro programma o una funzione devono supportare i numeri di lunghezza arbitraria (fino al limite stringa o di ingresso della vostra lingua) con uno degli operatori +, -o *. Alcuni altri esempi:

Ingresso:

ab + bd

Produzione:

acd

Ingresso:

d - ab

Produzione:

ac

Ingresso:

ab * cd

Produzione:

cf

Gli appunti:

  • L'ordine delle lettere nell'output non ha importanza, ma puoi sempre presumere che l'ordine delle lettere nei numeri nell'input sarà crescente (a prima di z).
  • È possibile accettare input con una nuova riga finale e output con una nuova riga finale.
  • Si può non prendere in ingresso come un elenco di ab, *e bdper ab * bd.
  • Viene utilizzato l'alfabeto inglese ( abcdefghijklmnopqrstuvwxyz)
  • L'output deve essere semplificato ( aanon è consentito, bè obbligatorio)
  • L'input sarà semplificato ( b+ c, non aa+ bbo aa+ aaaa)
  • Si può richiedere uno spazio prima e l'operatore ( +, -, o *), oppure si può richiedere che ci sia nessuno.
  • Ci sarà un solo operatore per input.
  • Si può presumere che l'output e l'input non supereranno mai 2 ^ 27-1 ( abcdefghijklmnopqrstuvwxyz)
  • Questo è , quindi vince la risposta più breve in byte!

2
d is 2 positions later in the alphabet than cè questo wright? non dovrebbe essere 1? That is added to the second row.sulla stessa frase, non dovrebbe essere third?
Felipe Nardi Batista,

1
@FelipeNardiBatista qui viene usato l'alfabeto inglese, modificato.
programmatore5

@ programmer5000 ancora, bc*de==efghma non lo efghè240144
Felipe Nardi Batista

1
bc*dedovrebbe essereeh
Felipe Nardi Batista il

@Dada ci sarà un solo operatore per input.
programmatore

Risposte:


3

Gelatina , 26 25 byte

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

Utilizza gli operatori di Jelly ( ×piuttosto che *e _piuttosto che -) nella stringa di input come consentito dall'OP .

(Richiede spazi attorno agli operatori)

Provalo online! o vedi la suite di test

Come?

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)

7

Mathematica, 168 byte

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

La mia soluzione iniziale (prima che il post fosse modificato per chiarire che l'output doveva essere semplificato) era di 64byte più breve:

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

Questo ha appena modificato quella soluzione per funzionare. Probabilmente è più breve utilizzare effettivamente i metodi descritti nella sfida, ma volevo comunque risolverlo.

Spiegazione:

Sostituisce ogni sequenza di lettere con il suo intero corrispondente con l'aritmetica del codice carattere, quindi converte la stringa risultante in un'espressione (che si semplifica automaticamente in un numero intero), quindi produce una stringa di acaratteri di lunghezza uguale a quell'intero e infine sostituisce identico adiacente caratteri con il codice carattere successivo fino a raggiungere un punto fisso.


2
Oh, non c'è un built-in a 1 carattere? Sorprendente!
programmatore5

7

JavaScript (ES6), 136 134 133 byte

Salvato 1 byte grazie a 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``

Casi test


Ben fatto! Mi hai battuto ...
programmer5000

Questo si converte in decimale e viceversa? Sembra così.
programmatore

1
@ programmer5000 Sì davvero. Sospetto che lo faranno molte risposte. (Tranne ovviamente Mathematica, che probabilmente ha un built-in per esso. ^^)
Arnauld

Sembra che nel tuo commento mancasse un link. Cos'è incorporato per esso?
programmatore

@ programmer5000 (In effetti, mancava una parola.)
Arnauld

5

Perl 5 , 95 byte

94 byte di codice + -pflag.

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

Provalo online!

Tre passaggi qui:
- s/\w/a x 2**(-97+ord$&)/ge;converte l'input in una stringa di asolo.
- s/(.*)-\1|+//;/*/&&($_=$`x length$')eseguirà l'operatore (che è molto semplice su stringhe di a): +è la concatenazione, -significa rimuovere dalla prima parte quante ane sono presenti nella seconda parte, e *significa duplicare la prima parte quante volte ci sono anella seconda parte.
- 1while s/(.)\1/chr 1+ord$1/ePiega le stesse lettere consecutive nella lettera successiva dell'alfabeto.


L'unica risposta che non converte in decimale! Bel lavoro!
programmatore

1
@ programmer5000 Su 2 risposte, non lo definirei così impressionante!
Dada,

5

05AB1E , 29 byte

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

Provalo online! o come una suite di test

Spiegazione

ð¡                             # 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

5

C & x86 asm, 340 byte

Compilare con -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);}}

Spiegazione

Dato che C non ha eval(), al suo posto ho usato una tabella di istruzioni x86. Ho dovuto scegliere istruzioni che fossero tutte della stessa lunghezza (o imbottite con nops) e che prevedessero src e destinazione degli stessi tipi. Di particolare fastidio è stato il fatto che il MUL può scrivere solo nei registri e che i codici operativi MUL a 1 byte possono scrivere solo su EAX. Inoltre, non sembrava esserci alcuna istruzione SUB per la scrittura di registri che sottrasse dalla memoria, invece del contrario, da qui l'XCHG.

modificare

Da quando è stato chiesto nei commenti, una valutazione più tradizionale sarebbe simile a questa:

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

In realtà è un po 'più breve, a 301 caratteri, per alcuni motivi: 1. Poiché ci devono essere molte funzioni, l'overhead di ciascuna può essere ridotto con alcune regole del preprocessore. 2. Il moderno linux protegge dall'esecuzione nello stack, quindi la chiamata mprotect () per disabilitare questo sacrificato 34 byte. 3. La chiamata XCHG è molto non ottimale e costa altri 30 byte. Se non fosse per queste cose, la combinazione x86 vincerebbe di circa 10-20 byte.

Tagliato anche 2 byte da entrambi migliorando la chiamata islower () in g.


Non posso davvero dire come si paragonerebbe a un approccio più classico in termini di dimensioni del codice, ma mi piace molto la tua soluzione. +1
Arnauld

5

GNU sed + coreutils, 329 byte

Sì, non ho idea di cosa mi sia preso, ma almeno so sed scripting un po 'meglio ora. Nota che questa soluzione richiede l' eestensione di GNU sed , che esegue un comando 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

Presumo che non ci saranno spazi attorno agli operatori. Dal mio terminale:

$ 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

E, per quelli più sani di me: la versione commentata!

#!/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

+1 per il codice sed e benvenuto in PPCG! La convenzione qui quando non si risolve in GNU sed puro (o in qualsiasi altro linguaggio puro), è quella di aggiungere al titolo i comandi di sistema utilizzati, ad esempio "GNU sed + coreutils", ad esempio, anche se nella descrizione si parla di chiamare un comando shell nella descrizione . Questo viene fatto per differenziare, specialmente nelle sfide con le classifiche, dalle risposte sed di GNU pure.
seshoumara,

Inoltre, ad eccezione del flag 'f' necessario ogni volta, ogni altro flag deve essere conteggiato come 1 byte. Quindi il tuo punteggio è 329. Potresti menzionarlo nella descrizione. E per il completamento, potresti pensare di aggiungere un link a un interprete sed online, come TIO .
seshoumara,

Per non essere tutto chiacchiere e nessuna azione, ecco un 43 byte più corto! versione del tuo codice (286 byte incluso -r), che ho trovato giocando a golf sui comandi. Sono sicuro che può essere ancora più breve.
seshoumara,

Ah, va bene, buono a sapersi! Inoltre, un bel golf! Quale versione di sed stai usando, però? Il tuo funziona in TIO, ma in GNU sed 4.4 ho appena ricevutosed: file golf.sed line 24: ":" lacks a label
charliegreen

L'etichetta senza nome è un bug ben noto in GNU sed, che è stato corretto nella versione 4.3. Ma su PPCG, puoi scrivere programmi per qualsiasi variante e versione di sed, usando i bug come funzionalità se aiuta a giocare a golf. Le differenze tra le versioni sono troppo piccole per essere menzionate (4.2 contro 4.4), ma la variante (POSIX standard vs GNU sed esteso) deve essere specificata nel titolo, con l'eventuale menzione dei programmi di sistema chiamati.
seshoumara,

4

PHP, 168

Uscita crescente con l'uso di 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 byte

Uscita crescente

[$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):"";

Versione online

allargato

[$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 byte

Decisione in uscita

[$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;

Versione online

allargato

[$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

4

Python 3 , 176 167 byte

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

Provalo online!


1
A meno che non mi sbagli, puoi radere due byte sostituendoli m>=2**(t+1)con m>=2**t*2e cinque byte sostituendoli a=a.split();m=eval(i(a[0])+a[1]+i(a[2]))con qualcosa del genere b,c,d=a.split();m=eval(i(b)+c+i(d)).
Tutleman,

1
Oh, e altri due byte sostituendoli 2**(ord(i)-97)con 1<<ord(i)-97.
Tutleman,

1
Sono sorpreso di quanto sia leggibile questa soluzione rispetto ad altre soluzioni.
Ole Tange,

Grazie :). Ma penso che sia anche perché il pitone è il linguaggio usato. Il rientro fa aumentare il conteggio dei byte, comunque leggibile. ;)
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):'';");

versione estesa:

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
     ");

Corri con php -R <code> .


1

AWK, 201 byte

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 vè il modo migliore che potrei fornire per fare un evaluatein AWK. Potrei "barare" un po 'per chiamarlo solo AWK, dato che sto eseguendo un comando, ma almeno il comando è anche AWK:)

Sono sicuro che mi manca un modo per ridurre il conteggio dei byte, ma di sicuro non riesco a vederlo.

L'utilizzo è abbastanza standard, ad esempio inserire il codice FILEe fare:

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

Si noti che gli spazi non sono richiesti e qualsiasi carattere non-op / non [az] verrà silenziosamente ignorato. Potrebbe essere esteso per funzionare con numeri maggiori di "abcdefghijklmnopqrstuvwxyz" modificando il loop. Per eseguire la divisione, aggiungi semplicemente il /carattere alla stringa dell'operazione :). Inoltre, stamperà una riga vuota se il result <= 0.

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.