Crea una calculadora omnifix

16

Inspiración. Inverso.

Evaluar una expresión omnifix dada.

Omnifix es como la notación infija de las matemáticas normales, pero con copias adicionales de cada símbolo que rodea los argumentos. Los símbolos externos toman el lugar de paréntesis y, por lo tanto, no hay necesidad de paréntesis adicionales.

Debe admitir sumas, restas, multiplicaciones, divisiones y números reales positivos (se pueden escribir los negativos -0-n-) dentro de un rango razonable para su idioma.

Más y menos deben ser +y -, pero puede usar *o ×por tiempos y / /o ÷dividir. Otros símbolos razonables serán permitidos a pedido.

Brownie señala la explicación y características adicionales (como operaciones adicionales, números negativos, cadenas, etc.) Incluso si su respuesta no tiene estas características, no dude en mostrar cómo podría.

Proporcione un enlace para probar su solución si es posible.

Ejemplos

Para mayor claridad, las explicaciones a continuación usan un alto menos ( ¯) para indicar números negativos. Puede devolver números negativos utilizando cualquier formato razonable.

-5-2-3

+2+×3×2×+8 ( +2+×3×2×++2+6+8)

-14--3-1--12 ( -4--3-1---14-2-12)

+2.1+×3.5×2.2×+9.8 ( +2.1+×3.5×2.2×++2.1+7.7+9.8)

×3×÷-0-6-÷2÷×-9 ( ×3×÷-0-6-÷2÷××3×÷¯6÷2÷××3ׯ3ׯ9)

÷4÷-3-÷1÷2÷-÷1.6 ( ÷4÷-3-÷1÷2÷-÷÷4÷-3-0.5-÷÷4÷2.5÷1.6)

Adán
fuente
1
The explanations below use high minus (`¯`) to indicate negative numbers.Definitivamente te encanta APL.
Erik the Outgolfer
@EriktheOutgolfer ¿Tienes alguna sugerencia mejor? Además, TI-BASIC usa un alto menos.
Adám
En realidad no, ya que -s puede confundirse con -s, mientras que ¯s no puede confundirse con -s.
Erik the Outgolfer
Bah, acabo de notar el requisito de número real. Esto en cuanto a mi solución de retina aritmética de enteros de 290 bytes ...
Neil
@Neil ¿Por qué no lo publicas como respuesta?
Adám

Respuestas:

4

C # (.NET Core) , 198 197 188 bytes

float O(string s){try{return float.Parse(s);}catch{var f=s[0];int i=s.IndexOf(f,1);float a=O(s.Substring(1,i-1)),b=O(s.Substring(i+1,s.Length-i-2));return f<43?a*b:f<44?a+b:f<46?a-b:a/b;}}

Pruébalo en línea!

Usos *y /.

Una función recursiva. Primero intenta analizar la cadena de entrada como a float. Si falla, se hace pasar recursivamente como argumentos el primer y segundo operandos y luego realiza la operación seleccionada en los resultados.

  • ¡1 byte guardado gracias al Sr. Xcoder!
  • ¡9 bytes guardados gracias a TheLethalCoder!
Charlie
fuente
IndefOf(f, 1)puede serIndexOf(f,1)
Sr. Xcoder
1
Use floats en su lugar, use los códigos char, cuando los tenga probablemente pueda acortarlos con >y <en un par de lugares.
TheLethalCoder
Puede jugar al golf cambiando i+1,s.Length-i-2a un byte ++i,s.Length+~i.
Kevin Cruijssen
4

Python 3, 159 158 152 144 136 135 132 bytes

def t(i,a=1):
 while'-'<l[i]!='/':i+=1;a=0
 if a:l[i]='(';i=t(t(i+1));l[i-1]=')'
 return-~i
*l,=input()
t(0)
print(eval(''.join(l)))

Pruébalo en línea!

No permite números negativos (aunque -0-5-funciona, por supuesto) y requiere operadores de python.

Arfie
fuente
¿Puedes agregar un enlace TIO?
Adám
1
while~-(l[i]in'+-*/'):i+=1;a=1y *l,=input()por 152 bytes
Felipe Nardi Batista
1
con todos los casos de prueba: enlace
Felipe Nardi Batista
1
144 bytes
Felipe Nardi Batista
1
if a:l[i]='(';i=t(t(i+1));l[i-1]=')'con return-~ipara 135 bytes: P
Felipe Nardi Batista
3

Retina , 290 287 286 bytes

\d+
¦$&$*
¯¦
¯
{`\+([¯¦]1*)\+([¯¦]1*)\+
-$1-¯$2-
-(¯|¦)(1*)-([¯¦]+1*\2)-
-¯$3-¯$1$2-
(×|÷)¯(1*\1)([¯¦]1*\1)
$1¦$2¯$3
צ×[¯¦]1*×|¯¯¦?
¦
¯¦|¦¯
¯
+`-((¯|¦)1*)(1*)-\2\3-
$1
-([¯¦]1*)-[¯¦](1*)-
$1$2
צ1(1*)×([¯¦]1*)×
+צ$1×$2×+$2+
}`÷¦(?=1*÷(¯|¦)(1+)÷)(\2)*1*÷\1\2÷
$1$#3$*
((¯)|¦)(1*)
$2$.3

Pruébalo en línea! Nota: Solo es capaz de aritmética de enteros, por lo que se han eliminado algunos de los casos de prueba. Acepta y devuelve números negativos usando el ¯prefijo. Editar: Guardado 3 4 bytes gracias a @Cowsquack. Explicación:

\d+
¦$&$*

Necesitaba alguna forma de manejar el cero, así que lo uso ¦como prefijo de número positivo. Los números se convierten a unario.

¯¦
¯

Pero los números negativos solo necesitan un ¯prefijo.

{`\+([¯¦]1*)\+([¯¦]1*)\+
-$1-¯$2-

Citar +s se pone feo, así que convierto las sumas en restas.

-(¯|¦)(1*)-([¯¦]+1*\2)-
-¯$3-¯$1$2-

Si el valor absoluto del LHS de una resta es menor que el RHS, cámbielos y niegue ambos lados.

(×|÷)¯(1*\1)([¯¦]1*\1)
$1¦$2¯$3

Además, si el LHS de una multiplicación o división es negativo, niegue ambos lados.

צ×[¯¦]1*×|¯¯¦?
¦

Además, si el LHS de una multiplicación es cero, entonces el resultado es cero. Además, dos desventajas hacen una ventaja.

¯¦|¦¯
¯

Pero un menos y un más (o viceversa) hacen un menos.

+`-((¯|¦)1*)(1*)-\2\3-
$1

Resta dos números del mismo signo. Haga esto repetidamente hasta que no queden tales restas.

-([¯¦]1*)-[¯¦](1*)-
$1$2

Si todavía hay una resta, los signos deben ser diferentes, así que suma los números. (Pero solo haga esto una vez, ya que esto puede revelar una resta de dos números del mismo signo nuevamente).

צ1(1*)×([¯¦]1*)×
+צ$1×$2×+$2+

Realizar multiplicación por suma repetida.

}`÷¦(?=1*÷(¯|¦)(1+)÷)(\2)*1*÷\1\2÷
$1$#3$*

Realizar división entera. Uno de los pasos anteriores habrá simplificado la expresión, así que retrocede hasta que no queden operaciones.

((¯)|¦)(1*)
$2$.3

Convertir de nuevo a decimal.

Neil
fuente
Wow, eso es épico. ¿La mayor publicación de Retina en PPCG? Sin embargo, generalmente las soluciones QuadR y Retina se parecen mucho entre sí. ¿Tal vez puedo inspirar?
Adám
En esta línea +`-(([¯¦])1*)(1*)-\2\3-, [¯¦]puede convertirse¯|¦
Kritixi Lithos
@Cowsquack sucede tres veces, de hecho, ¡gracias!
Neil
Hay uno que te perdiste ([×÷]);)
Kritixi Lithos
1
@Cowsquack Será mejor que no encuentres otro, de lo contrario tendré que tachar 4 ...
Neil
2

PHP , 116 114 109 bytes

-5 gracias a Martin Ender

for($s=$argv[$o=1];$o!=$s;)$s=preg_replace('#([*+/-])(([\d.]+|(?R))\1(?3))\1#','($2)',$o=$s);eval("echo$s;");

Usos *para multiplicación y /para división. Los números negativos funcionan a pesar de que no hice ningún intento específico para que ese sea el caso.

Pruébalo en línea!

Sin golf y explicado

for($s=$argv[$o=1];   # Initialize with $s = input and $o = 1;
    $o!=$s;)          # While $o != $s
    # Set $o to $s and set $s to be $s after this regex replacement:
    $s=preg_replace('#([*+/-])(([\d.]+|(?R))\1(?3))\1#','($2)',$o=$s);
    # i.e., continue to do this replacement until the result is the same on two consecutive
    # steps (no replacement was made)
# Once $o == $s (i.e. no more replacement can be made), eval the result and print
eval("echo$s;"); 

También explicaré la expresión regular porque es un poco mágica:

([*+/-])(([\d.]+|(?R))\1(?3))\1


([*+/-])

Primero, queremos igualar cualquiera de los cuatro operadores: *+/-

([\d.]+|(?R))

Luego, debemos hacer coincidir un número [\d.]+u otra expresión omnifix válida (?R).

\1

Luego, hacemos coincidir el mismo operador que estaba al principio.

(?3)

Luego hacemos lo mismo que hicimos en el grupo 3: unir un número o una expresión omnifix.

\1

Finalmente, haga coincidir el operador inicial nuevamente.

Lo que coincida con esto se reemplaza con ($2). Esto toma la parte dentro de los operadores circundantes y lo pone entre paréntesis, por lo que parece una notación infija normal.

Gato de negocios
fuente
2

QuadR , 33 32 27 bytes

-1 gracias a Cows Quack . -5 gracias a Erik the Outgolfer .

((.)[\d¯\.]+){2}\2
⍎¯11↓⍵M

con el argumento / bandera

Pruébalo en línea!

Esto es equivalente a la solución Dyalog APL de 40 bytes:

'((.)[\d¯\.]+){2}\2'R{⍕⍎1↓¯1↓⍵.Match}⍣≡

Pruébalo en línea!

Explicación

(el texto entre paréntesis se refiere a Dyalog APL en lugar de QuadR)

(... ){2}\2 el siguiente patrón dos veces, y todo el partido dos veces demasiado:
  (.) cualquier carácter
  [... ]+ seguido de uno o más de los siguientes conjunto de caracteres:
   \dd igits,
   ¯ alta menos (signo negativo)
   \. período

( ⎕R Se R eplaced con :)

( {... } el resultado de la siguiente función anónima aplicada al espacio de nombres ⍵ :)

⍵M ( ⍵.Match) el texto de M atch
¯1↓ suelta el último carácter (el símbolo + - ×o ÷)
1↓ suelta el primer carácter (símbolo)
 ejecutar como código APL
 (  stringify)

 ( ⍣≡) repita el reemplazo hasta que no ocurran más cambios

Adán
fuente
Creo que puedes caer
Kritixi Lithos
@Cowsquack Tienes razón sobre QuadR. ⎕Rno puede funcionar con datos numéricos. Gracias.
Adám
1

Haskell , 132 caracteres

(134 bytes, porque ×y ÷toma dos bytes en UTF-8)

f y|(n@(_:_),r)<-span(`elem`['.'..'9'])y=(read n,r)
f(c:d)|(l,_:s)<-f d,(m,_:r)<-f s=(o[c]l m,r)
o"+"=(+)
o"-"=(-)
o"×"=(*)
o"÷"=(/)

Pruébalo en línea!

fanaliza la mayor cantidad de entrada posible y produce el resultado, así como la cadena restante (que está vacía en los casos de prueba). Si eso no cumple con las reglas, pele la cadena del resto que no se puede analizar con

Haskell , 139 caracteres

...
g=fst.f
dejó de girar en sentido antihorario
fuente
0

Perl, 64 53 bytes

Incluir +1para-p

perl -pe 's%([*-/])(([\d.]+|(?0))\1(?3))\1%($2)%&&redo;$_=eval' <<< "/4/-3-/1/2/-/"

Accidentalmente también implementa ,(desecha el primer argumento) y, a veces .(agrega los argumentos juntos). .sin embargo, no funciona de manera muy confiable ya que interfiere con el punto decimal tanto en el nivel de análisis como en el nivel de evaluación

Ton Hospel
fuente
0

Java 8, 205 200 bytes

float O(String s){try{return new Float(s);}catch(Exception e){int f=s.charAt(0),i=s.indexOf(f,1);float a=O(s.substring(1,i)),b=O(s.substring(i+1,s.length()-1));return f<43?a*b:f<44?a+b:f<46?a-b:a/b;}}

Puerto de la respuesta C # de @Charlie .
-5 bytes gracias a @ceilingcat .

Pruébalo en línea.

Kevin Cruijssen
fuente