Hagamos algo de aritmética de ubicación


22

Del artículo de Wikipedia :

La ubicación aritmética (Latin arithmeticæ localis) es el sistema de numeración binario aditivo (no posicional), que John Napier exploró como una técnica de cálculo en su tratado Rabdology (1617), tanto simbólicamente como en una cuadrícula similar a un tablero de ajedrez.

¿Qué?

Los números de ubicación son una forma de escribir números usando letras del alfabeto.

La notación binaria aún no se había estandarizado, por lo que Napier usó lo que llamó números de ubicación para representar números binarios. El sistema de Napier utiliza la notación de signo y valor para representar números; utiliza letras sucesivas del alfabeto inglés para representar potencias sucesivas de dos: a = 2 ^ 0 = 1, b = 2 ^ 1 = 2, c = 2 ^ 2 = 4, d = 2 ^ 3 = 8, e = 2 ^ 4 = 16 y así sucesivamente.

Un ejemplo

ab = 1 + 2 = 3 en base 10

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

Tenga en cuenta que aabbpuede acortarse bcreemplazando 2 instancias de una letra por una superior.

Adición

Simplemente concatena los dos números y simplifica.

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

Sustracción

Simplemente elimine todos los dígitos que aparecen igualmente en ambas partes de la resta. Puede ser necesario expandir (convertir ba aa)

abde- ad= be= 18 en base 10

Multiplicación

Esto es un poco más difícil.

Digamos que queremos multiplicar acd(13) por def(56). Primero arreglas acdverticalmente:

a
c
d

Luego agrega defdespués del primero a:

a def
c
d

Ahora, c es 2 posiciones más tarde en el alfabeto que a, así que agregamos 2 posiciones en el alfabeto defpara hacer fgh. Eso se agrega a la segunda fila.

a def
c fgh
d

Por último, d es 1 posición más tarde en el alfabeto que c, por lo que agregamos 1 posición en el alfabeto fghpara hacer ghi. Eso se agrega a la tercera fila.

a def
c fgh
d ghi

Luego tomas la suma de la derecha: def+ fgh+ ghi= deffgghhi= deggghhi= deghhhi= deghii=deghj (728)

Otro ejemplo de multiplicación.

Entrada:

bc * de

Primero:

b
c

Luego

b ef
c 

Luego

b ef
c fg

Tenga en cuenta que escribimos efen la primera línea. Esto se debe a que bccomienza con by bes la segunda letra del alfabeto, por lo que debemos cambiar de1 letra para que se convierta ef.

Luego

ef+fg

Salida:

eh

División

Esto no es parte de este desafío, porque puede volverse muy complejo.

Tu verdadero desafío

Su programa o función debe tomar la entrada como una cadena que se ve así:

a + b

Y debes dar salida:

ab

Por supuesto, el programa o función debe ser compatible con los números de longitud arbitraria (hasta el límite de la cadena o de entrada de la lengua) con cualquiera de los operadores +, -o* . Algunos ejemplos más:

Entrada:

ab + bd

Salida:

acd

Entrada:

d - ab

Salida:

ac

Entrada:

ab * cd

Salida:

cf

Notas:

  • El orden de las letras en la salida no importa, pero siempre se puede suponer que el orden de las letras en los números en la entrada será ascendente (a antes de z).
  • Puede tomar la entrada con una nueva línea final y la salida con una nueva línea final.
  • Es posible que no tomar la entrada como una lista de ab, *y bdparaab * bd .
  • Se usa el alfabeto inglés (abcdefghijklmnopqrstuvwxyz )
  • Su salida debe ser simplificada ( aano está permitido,b es obligatorio)
  • La entrada se simplificará ( b+ c, no aa+ bbo aa+ aaaa)
  • Es posible que necesite un espacio antes y el operador ( +, -o* ), o tal vez necesite que haya ninguna.
  • Solo habrá un operador por entrada.
  • Puede suponer que la salida y la entrada nunca superarán 2 ^ 27-1 ( abcdefghijklmnopqrstuvwxyz)
  • Este es el , por lo que gana la respuesta más corta en bytes.

2
d is 2 positions later in the alphabet than ces este wright? no debería ser 1? That is added to the second row.en la misma oración, ¿no debería ser así third?
Felipe Nardi Batista

1
@FelipeNardiBatista aquí se usa el alfabeto inglés, editado eso.
programmer5000

@ programmer5000 todavía, bc*de==efghpero no lo efghes240144
Felipe Nardi Batista

1
bc*dedebería sereh
Felipe Nardi Batista

@Dada solo habrá un operador por entrada.
programmer5000

Respuestas:


3

Jalea , 26 25 bytes

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

Utiliza los operadores de Jelly (en ×lugar de *y en _lugar de -) en la cadena de entrada según lo permitido por el OP .

(Requiere espacios alrededor de los operadores)

Pruébalo en línea! o ver el conjunto de pruebas

¿Cómo?

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 bytes

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

Mi solución inicial (antes de que se editara la publicación para aclarar que la salida debe simplificarse) fue 64bytes más cortos:

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

Esto simplemente modificó esa solución para que funcione. Probablemente sea más corto usar los métodos descritos en el desafío, pero de todos modos quería poner esto en práctica.

Explicación:

Reemplaza cada secuencia de letras con su entero correspondiente por aritmética de código de caracteres, luego convierte la cadena resultante en una expresión (que se simplificará automáticamente a un entero), luego produce una cadena de acaracteres de longitud igual a ese entero y finalmente reemplaza idéntico adyacente caracteres con el siguiente código de caracteres hasta llegar a un punto fijo.


2
Oh, no hay 1-char incorporado? Sorprendente!
programmer5000

7

JavaScript (ES6), 136 134 133 bytes

Guardado 1 byte gracias 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``

Casos de prueba


¡Bien hecho! Me ganaste ...
programmer5000

¿Esto se convierte a decimal y viceversa? Parece que sí.
programmer5000

1
@ programmer5000 Sí, de hecho. Sospecho que muchas respuestas lo harán. (Excepto, por supuesto, Mathematica, que probablemente tiene una función incorporada. ^^)
Arnauld

Parece que a tu comentario le faltaba un enlace. ¿Qué tiene un fot incorporado?
programmer5000

@ programmer5000 (De hecho, le faltaba una palabra.)
Arnauld

5

Perl 5 , 95 bytes

94 bytes de código + -pbandera.

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

Pruébalo en línea!

Tres pasos aquí:
- s/\w/a x 2**(-97+ord$&)/ge;convierte la entrada en una cadena de asolamente.
- s/(.*)-\1|+//;/*/&&($_=$`x length$')ejecutará el operador (que son muy simples en cadenas de a): +es la concatenación, -significa eliminar de la primera parte tantas acomo haya en la segunda parte, y *significa duplicar la primera parte tantas veces como haya aen la segunda parte.
- 1while s/(.)\1/chr 1+ord$1/edobla las mismas letras consecutivas en la siguiente letra del alfabeto.


¡La única respuesta que no se convierte a decimal! ¡Buen trabajo!
programmer5000

1
@ programmer5000 De 2 respuestas, ¡no lo llamaría impresionante!
Dada

5

05AB1E , 29 bytes

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

Pruébalo en línea! o como un conjunto de pruebas

Explicación

ð¡                             # 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 y x86 asm, 340 bytes

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

Explicación

Como C no tiene eval(), usé una tabla de instrucciones x86 en su lugar. Tuve que elegir instrucciones que fueran todas de la misma longitud (o rellenadas con nops), y que esperaran src y el destino de los mismos tipos. De particular molestia fue que MUL solo puede escribir en registros, y los códigos de operación de 1 byte MUL solo pueden escribir en EAX. Además, no parecía haber ninguna instrucción SUB de escritura de registros que se restara de la memoria, en lugar de lo contrario, de ahí el XCHG.

editar

Como se preguntó en los comentarios, una aproximación más tradicional se vería así:

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

En realidad es un poco más corto, con 301 caracteres, por algunas razones: 1. Debido a que debe haber muchas funciones, la sobrecarga de cada una se puede cortar con algunas reglas de preprocesador. 2. Linux moderno protege de la ejecución en la pila, por lo que la llamada mprotect () para deshabilitar esto sacrificó 34 bytes. 3. La llamada XCHG es muy subóptima y cuesta otros 30 bytes. Si no fuera por esas cosas, el combo x86 ganaría unos 10-20 bytes.

También cortó 2 bytes de ambos mejorando la llamada islower () en g.


Realmente no puedo decir cómo se compararía con un enfoque más clásico en términos de tamaño de código, pero realmente me gusta su solución. +1
Arnauld

5

GNU sed + coreutils, 329 bytes

Sí, no tengo idea de lo que me pasó, pero al menos sé que las secuencias de comandos de sed ahora son un poco mejores. Tenga en cuenta que esta solución requiere la eextensión de GNU sed , que ejecuta un comando de 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

Supongo que no habrá espacios alrededor de los operadores. Desde mi 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

Y, para aquellos más cuerdos que yo: ¡la versión comentada!

#!/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 para el código sed y bienvenido a PPCG! La convención aquí cuando no se resuelve en puro GNU sed (o en cualquier otro lenguaje puro), es agregar al título los comandos del sistema utilizados, como "GNU sed + coreutils", por ejemplo, incluso si menciona llamar a un comando de shell en la descripción . Esto se hace para diferenciar, especialmente en los desafíos con tablas de clasificación, de respuestas puras de GNU sed.
seshoumara

Además, a excepción de la bandera 'f' necesaria cada vez, cualquier otra bandera debe contarse como 1 byte. Entonces su puntaje es 329. Es posible que desee mencionar eso en la descripción. Y para completar, puede pensar en agregar un enlace a un intérprete de sed en línea, como TIO .
seshoumara

Para no ser todo hablar y no actuar, ¡ aquí hay 43 bytes más cortos! versión de su código (286 bytes incluyendo -r), que encontré jugando golf a los comandos. Estoy seguro de que puede ser aún más corto.
seshoumara

Ah, está bien, es bueno saberlo! Además, buen golf! ¿Qué versión de sed estás usando? El tuyo funciona en TIO, pero en GNU sed 4.4 acabo de obtenersed: file golf.sed line 24: ":" lacks a label
charliegreen

La etiqueta sin nombre es un error bien conocido en GNU sed, que se corrigió en la versión 4.3. Pero en PPCG, puede escribir programas para cualquier variante y versión sed, utilizando errores como características si ayuda en el golf. Las diferencias entre las versiones son demasiado pequeñas para mencionarlas (4.2 frente a 4.4), pero la variante (POSIX estándar vs GNU extendido) debe especificarse en el título, con la mención de los programas del sistema llamados, si los hay.
seshoumara

4

PHP, 168

Salida ascendente con el uso 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 bytes

Salida ascendente

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

Versión en línea

Expandido

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

Salida descendente

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

Versión en línea

Expandido

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

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

Pruébalo en línea!


1
A menos que me equivoque, puede eliminar dos bytes reemplazándolos m>=2**(t+1)con m>=2**t*2, y cinco bytes reemplazándolos a=a.split();m=eval(i(a[0])+a[1]+i(a[2]))con algo así b,c,d=a.split();m=eval(i(b)+c+i(d)).
Tutleman

1
Ah, y dos bytes más al reemplazar 2**(ord(i)-97)con 1<<ord(i)-97.
Tutleman

1
Estoy sorprendido de lo legible que es esta solución en comparación con otras soluciones.
Ole Tange

Gracias :). Pero creo que también se debe a que Python es el lenguaje utilizado. La sangría hace que el recuento de bytes aumente, aunque sea legible. ;)
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):'';");

versión expandida:

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

corre con php -R <code> .


1

AWK, 201 bytes

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 ves la mejor manera de que pudiera llegar a hacer una evaluateen AWK. Puedo estar "engañando" un poco para llamar a esto solo AWK, ya que estoy ejecutando un comando, pero al menos el comando también es AWK:)

Estoy seguro de que me falta alguna forma de reducir el conteo de bytes, pero estoy seguro de que no puedo verlo.

El uso es bastante estándar, por ejemplo, ingrese el código FILEy haga:

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

Tenga en cuenta que no se requieren espacios y cualquier carácter no operativo / no [az] se ignorará en silencio. Podría extenderse para trabajar con números mayores que "abcdefghijklmnopqrstuvwxyz" cambiando el ciclo. Para hacer la división, simplemente agregue el /carácter a la cadena de operación :). Además, imprimirá una línea en blanco si el result <= 0.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.