# Calculadora prefija (c) Baltasar 2022 MIT License <jbgarcia@uvigo.es>
"""
Esta calculadora acepta entradas del tipo: + 4 5
Para calcularlas como 4 + 5 y devolver 9.
La ventaja de los formatos prefijo (los operadores preceden a los operandos),
y postfijo (los operadores siguen a los operandos), es que no necesitan paréntesis.
Un ejemplo de expresión compleja sería: + 1 * 4 / 6 2, que sería evaluada como:
+ 1 * 4 / 6 2 => + 1 * 4 3 => + 1 12 = 13
"""
import math
def opera(opr: str, op1: float, op2: float) -> float:
"""
Calcula una expresión simple, como 4 * 2.
:param opr: El operador, como *, +, -...
:param op1: Un num. real.
:param op2: Un num. real.
:return: El resultado.
"""
match = {
'+': lambda x, y: x + y,
'-': lambda x, y: x - y,
'*': lambda x, y: x * y,
'/': lambda x, y: x / y if y != 0 else math.nan,
'^': lambda x, y: math.pow(op1, op2),
}
fn = match.get(opr)
return math.nan if not fn else fn(op1, op2)
def calculadora_prefija_iterativa(lexpr: list) -> float:
"""
Acepta una lista de operadores y operandos y devuelve el resultado.
Funciona empleando una pila de operaciones. Cada elemento de la pila
es una lista [opr, op1, op2], donde opr es el operador, op1 y op2 los operandos.
Cada nuevo operador encontrado añade una nueva entrada en la lista, mientras
que un operando puede suponer añadirlo a la operación actual e incluso
resolverla, si se trata del último operando (op2).
:param lexpr: Una lista de operadores y operandos, como texto.
:return: El resultado numérico.
"""
operadores = "+-*/^"
parciales = []
current = None
while lexpr:
opn = lexpr[0]
if opn in operadores:
current = [opn]
parciales.append(current)
else:
current.append(float(opn))
while current and len(current) == 3:
res = opera(current[0], current[1], current[2])
parciales.pop()
if parciales:
current = parciales[-1]
current.append(res)
else:
current = None
parciales.append(res)
lexpr.pop(0)
if len(parciales) == 1:
return parciales[0]
else:
return math.nan
def calculadora_prefija_recursiva(lexpr: list) -> float:
"""
Acepta una lista de operadores y operandos y devuelve el resultado.
:param lexpr: Una lista de operadores y operandos, como texto.
:return: El resultado numérico.
"""
opr = lexpr.pop(0) if lexpr else ""
# Primer operando
op1 = lexpr[0] if lexpr else str(math.nan)
try:
op1 = float(op1)
if lexpr: lexpr.pop(0)
except ValueError:
op1 = calculadora_prefija_recursiva(lexpr)
# Segundo operando
op2 = lexpr[0] if lexpr else str(math.nan)
try:
op2 = float(op2)
if lexpr: lexpr.pop(0)
except ValueError:
op2 = calculadora_prefija_recursiva(lexpr)
return opera(opr, op1, op2)
if __name__ == "__main__":
expr = input("Dame un expr.: ").strip()
lexpr = expr.strip().split()
if lexpr:
try:
float(lexpr[0])
lexpr.reverse()
except ValueError:
pass
res = calculadora_prefija_iterativa(lexpr)
print(expr, "=", res)
else:
print("Expr. incorrecta")
IyBDYWxjdWxhZG9yYSBwcmVmaWphIChjKSBCYWx0YXNhciAyMDIyIE1JVCBMaWNlbnNlIDxqYmdhcmNpYUB1dmlnby5lcz4KIiIiCkVzdGEgY2FsY3VsYWRvcmEgYWNlcHRhIGVudHJhZGFzIGRlbCB0aXBvOiArIDQgNQpQYXJhIGNhbGN1bGFybGFzIGNvbW8gNCArIDUgeSBkZXZvbHZlciA5LgpMYSB2ZW50YWphIGRlIGxvcyBmb3JtYXRvcyBwcmVmaWpvIChsb3Mgb3BlcmFkb3JlcyBwcmVjZWRlbiBhIGxvcyBvcGVyYW5kb3MpLAp5IHBvc3RmaWpvIChsb3Mgb3BlcmFkb3JlcyBzaWd1ZW4gYSBsb3Mgb3BlcmFuZG9zKSwgZXMgcXVlIG5vIG5lY2VzaXRhbiBwYXLDqW50ZXNpcy4KVW4gZWplbXBsbyBkZSBleHByZXNpw7NuIGNvbXBsZWphIHNlcsOtYTogKyAxICogNCAvIDYgMiwgcXVlIHNlcsOtYSBldmFsdWFkYSBjb21vOgorIDEgKiA0IC8gNiAyID0+ICsgMSAqIDQgMyA9PiArIDEgMTIgPSAxMwoiIiIKCgppbXBvcnQgbWF0aAoKCmRlZiBvcGVyYShvcHI6IHN0ciwgb3AxOiBmbG9hdCwgb3AyOiBmbG9hdCkgLT4gZmxvYXQ6CiAgICAiIiIKICAgIENhbGN1bGEgdW5hIGV4cHJlc2nDs24gc2ltcGxlLCBjb21vIDQgKiAyLgogICAgOnBhcmFtIG9wcjogRWwgb3BlcmFkb3IsIGNvbW8gKiwgKywgLS4uLgogICAgOnBhcmFtIG9wMTogVW4gbnVtLiByZWFsLgogICAgOnBhcmFtIG9wMjogVW4gbnVtLiByZWFsLgogICAgOnJldHVybjogRWwgcmVzdWx0YWRvLgogICAgIiIiCiAgICBtYXRjaCA9IHsKICAgICAgICAnKyc6IGxhbWJkYSB4LCB5OiB4ICsgeSwKICAgICAgICAnLSc6IGxhbWJkYSB4LCB5OiB4IC0geSwKICAgICAgICAnKic6IGxhbWJkYSB4LCB5OiB4ICogeSwKICAgICAgICAnLyc6IGxhbWJkYSB4LCB5OiB4IC8geSBpZiB5ICE9IDAgZWxzZSBtYXRoLm5hbiwKICAgICAgICAnXic6IGxhbWJkYSB4LCB5OiBtYXRoLnBvdyhvcDEsIG9wMiksCiAgICB9CgogICAgZm4gPSBtYXRjaC5nZXQob3ByKQogICAgcmV0dXJuIG1hdGgubmFuIGlmIG5vdCBmbiBlbHNlIGZuKG9wMSwgb3AyKQoKCmRlZiBjYWxjdWxhZG9yYV9wcmVmaWphX2l0ZXJhdGl2YShsZXhwcjogbGlzdCkgLT4gZmxvYXQ6CiAgICAiIiIKICAgIEFjZXB0YSB1bmEgbGlzdGEgZGUgb3BlcmFkb3JlcyB5IG9wZXJhbmRvcyB5IGRldnVlbHZlIGVsIHJlc3VsdGFkby4KICAgIEZ1bmNpb25hIGVtcGxlYW5kbyB1bmEgcGlsYSBkZSBvcGVyYWNpb25lcy4gQ2FkYSBlbGVtZW50byBkZSBsYSBwaWxhCiAgICBlcyB1bmEgbGlzdGEgW29wciwgb3AxLCBvcDJdLCBkb25kZSBvcHIgZXMgZWwgb3BlcmFkb3IsIG9wMSB5IG9wMiBsb3Mgb3BlcmFuZG9zLgogICAgQ2FkYSBudWV2byBvcGVyYWRvciBlbmNvbnRyYWRvIGHDsWFkZSB1bmEgbnVldmEgZW50cmFkYSBlbiBsYSBsaXN0YSwgbWllbnRyYXMKICAgIHF1ZSB1biBvcGVyYW5kbyBwdWVkZSBzdXBvbmVyIGHDsWFkaXJsbyBhIGxhIG9wZXJhY2nDs24gYWN0dWFsIGUgaW5jbHVzbwogICAgcmVzb2x2ZXJsYSwgc2kgc2UgdHJhdGEgZGVsIMO6bHRpbW8gb3BlcmFuZG8gKG9wMikuCiAgICA6cGFyYW0gbGV4cHI6IFVuYSBsaXN0YSBkZSBvcGVyYWRvcmVzIHkgb3BlcmFuZG9zLCBjb21vIHRleHRvLgogICAgOnJldHVybjogRWwgcmVzdWx0YWRvIG51bcOpcmljby4KICAgICIiIgogICAgb3BlcmFkb3JlcyA9ICIrLSovXiIKICAgIHBhcmNpYWxlcyA9IFtdCiAgICBjdXJyZW50ID0gTm9uZQoKICAgIHdoaWxlIGxleHByOgogICAgICAgIG9wbiA9IGxleHByWzBdCiAgICAgICAgaWYgb3BuIGluIG9wZXJhZG9yZXM6CiAgICAgICAgICAgIGN1cnJlbnQgPSBbb3BuXQogICAgICAgICAgICBwYXJjaWFsZXMuYXBwZW5kKGN1cnJlbnQpCiAgICAgICAgZWxzZToKICAgICAgICAgICAgY3VycmVudC5hcHBlbmQoZmxvYXQob3BuKSkKCiAgICAgICAgICAgIHdoaWxlIGN1cnJlbnQgYW5kIGxlbihjdXJyZW50KSA9PSAzOgogICAgICAgICAgICAgICAgcmVzID0gb3BlcmEoY3VycmVudFswXSwgY3VycmVudFsxXSwgY3VycmVudFsyXSkKICAgICAgICAgICAgICAgIHBhcmNpYWxlcy5wb3AoKQogICAgICAgICAgICAgICAgaWYgcGFyY2lhbGVzOgogICAgICAgICAgICAgICAgICAgIGN1cnJlbnQgPSBwYXJjaWFsZXNbLTFdCiAgICAgICAgICAgICAgICAgICAgY3VycmVudC5hcHBlbmQocmVzKQogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICBjdXJyZW50ID0gTm9uZQogICAgICAgICAgICAgICAgICAgIHBhcmNpYWxlcy5hcHBlbmQocmVzKQoKICAgICAgICBsZXhwci5wb3AoMCkKCiAgICBpZiBsZW4ocGFyY2lhbGVzKSA9PSAxOgogICAgICAgIHJldHVybiBwYXJjaWFsZXNbMF0KICAgIGVsc2U6CiAgICAgICAgcmV0dXJuIG1hdGgubmFuCgoKZGVmIGNhbGN1bGFkb3JhX3ByZWZpamFfcmVjdXJzaXZhKGxleHByOiBsaXN0KSAtPiBmbG9hdDoKICAgICIiIgogICAgQWNlcHRhIHVuYSBsaXN0YSBkZSBvcGVyYWRvcmVzIHkgb3BlcmFuZG9zIHkgZGV2dWVsdmUgZWwgcmVzdWx0YWRvLgogICAgOnBhcmFtIGxleHByOiBVbmEgbGlzdGEgZGUgb3BlcmFkb3JlcyB5IG9wZXJhbmRvcywgY29tbyB0ZXh0by4KICAgIDpyZXR1cm46IEVsIHJlc3VsdGFkbyBudW3DqXJpY28uCiAgICAiIiIKICAgIG9wciA9IGxleHByLnBvcCgwKSBpZiBsZXhwciBlbHNlICIiCgogICAgIyBQcmltZXIgb3BlcmFuZG8KICAgIG9wMSA9IGxleHByWzBdIGlmIGxleHByIGVsc2Ugc3RyKG1hdGgubmFuKQoKICAgIHRyeToKICAgICAgICBvcDEgPSBmbG9hdChvcDEpCiAgICAgICAgaWYgbGV4cHI6IGxleHByLnBvcCgwKQogICAgZXhjZXB0IFZhbHVlRXJyb3I6CiAgICAgICAgb3AxID0gY2FsY3VsYWRvcmFfcHJlZmlqYV9yZWN1cnNpdmEobGV4cHIpCgogICAgIyBTZWd1bmRvIG9wZXJhbmRvCiAgICBvcDIgPSBsZXhwclswXSBpZiBsZXhwciBlbHNlIHN0cihtYXRoLm5hbikKCiAgICB0cnk6CiAgICAgICAgb3AyID0gZmxvYXQob3AyKQogICAgICAgIGlmIGxleHByOiBsZXhwci5wb3AoMCkKICAgIGV4Y2VwdCBWYWx1ZUVycm9yOgogICAgICAgIG9wMiA9IGNhbGN1bGFkb3JhX3ByZWZpamFfcmVjdXJzaXZhKGxleHByKQoKICAgIHJldHVybiBvcGVyYShvcHIsIG9wMSwgb3AyKQoKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICBleHByID0gaW5wdXQoIkRhbWUgdW4gZXhwci46ICIpLnN0cmlwKCkKICAgIGxleHByID0gZXhwci5zdHJpcCgpLnNwbGl0KCkKCiAgICBpZiBsZXhwcjoKICAgICAgICB0cnk6CiAgICAgICAgICAgIGZsb2F0KGxleHByWzBdKQogICAgICAgICAgICBsZXhwci5yZXZlcnNlKCkKICAgICAgICBleGNlcHQgVmFsdWVFcnJvcjoKICAgICAgICAgICAgcGFzcwoKICAgICAgICByZXMgPSBjYWxjdWxhZG9yYV9wcmVmaWphX2l0ZXJhdGl2YShsZXhwcikKICAgICAgICBwcmludChleHByLCAiPSIsIHJlcykKICAgIGVsc2U6CiAgICAgICAgcHJpbnQoIkV4cHIuIGluY29ycmVjdGEiKQo=