fork download
  1. # Calculadora prefija (c) Baltasar 2022 MIT License <jbgarcia@uvigo.es>
  2. """
  3. Esta calculadora acepta entradas del tipo: + 4 5
  4. Para calcularlas como 4 + 5 y devolver 9.
  5. La ventaja de los formatos prefijo (los operadores preceden a los operandos),
  6. y postfijo (los operadores siguen a los operandos), es que no necesitan paréntesis.
  7. Un ejemplo de expresión compleja sería: + 1 * 4 / 6 2, que sería evaluada como:
  8. + 1 * 4 / 6 2 => + 1 * 4 3 => + 1 12 = 13
  9. """
  10.  
  11.  
  12. import math
  13.  
  14.  
  15. def opera(opr: str, op1: float, op2: float) -> float:
  16. """
  17. Calcula una expresión simple, como 4 * 2.
  18. :param opr: El operador, como *, +, -...
  19. :param op1: Un num. real.
  20. :param op2: Un num. real.
  21. :return: El resultado.
  22. """
  23. match = {
  24. '+': lambda x, y: x + y,
  25. '-': lambda x, y: x - y,
  26. '*': lambda x, y: x * y,
  27. '/': lambda x, y: x / y if y != 0 else math.nan,
  28. '^': lambda x, y: math.pow(op1, op2),
  29. }
  30.  
  31. fn = match.get(opr)
  32. return math.nan if not fn else fn(op1, op2)
  33.  
  34.  
  35. def calculadora_prefija_iterativa(lexpr: list) -> float:
  36. """
  37. Acepta una lista de operadores y operandos y devuelve el resultado.
  38. Funciona empleando una pila de operaciones. Cada elemento de la pila
  39. es una lista [opr, op1, op2], donde opr es el operador, op1 y op2 los operandos.
  40. Cada nuevo operador encontrado añade una nueva entrada en la lista, mientras
  41. que un operando puede suponer añadirlo a la operación actual e incluso
  42. resolverla, si se trata del último operando (op2).
  43. :param lexpr: Una lista de operadores y operandos, como texto.
  44. :return: El resultado numérico.
  45. """
  46. operadores = "+-*/^"
  47. parciales = []
  48. current = None
  49.  
  50. while lexpr:
  51. opn = lexpr[0]
  52. if opn in operadores:
  53. current = [opn]
  54. parciales.append(current)
  55. else:
  56. current.append(float(opn))
  57.  
  58. while current and len(current) == 3:
  59. res = opera(current[0], current[1], current[2])
  60. parciales.pop()
  61. if parciales:
  62. current = parciales[-1]
  63. current.append(res)
  64. else:
  65. current = None
  66. parciales.append(res)
  67.  
  68. lexpr.pop(0)
  69.  
  70. if len(parciales) == 1:
  71. return parciales[0]
  72. else:
  73. return math.nan
  74.  
  75.  
  76. def calculadora_prefija_recursiva(lexpr: list) -> float:
  77. """
  78. Acepta una lista de operadores y operandos y devuelve el resultado.
  79. :param lexpr: Una lista de operadores y operandos, como texto.
  80. :return: El resultado numérico.
  81. """
  82. opr = lexpr.pop(0) if lexpr else ""
  83.  
  84. # Primer operando
  85. op1 = lexpr[0] if lexpr else str(math.nan)
  86.  
  87. try:
  88. op1 = float(op1)
  89. if lexpr: lexpr.pop(0)
  90. except ValueError:
  91. op1 = calculadora_prefija_recursiva(lexpr)
  92.  
  93. # Segundo operando
  94. op2 = lexpr[0] if lexpr else str(math.nan)
  95.  
  96. try:
  97. op2 = float(op2)
  98. if lexpr: lexpr.pop(0)
  99. except ValueError:
  100. op2 = calculadora_prefija_recursiva(lexpr)
  101.  
  102. return opera(opr, op1, op2)
  103.  
  104.  
  105. if __name__ == "__main__":
  106. expr = input("Dame un expr.: ").strip()
  107. lexpr = expr.strip().split()
  108.  
  109. if lexpr:
  110. try:
  111. float(lexpr[0])
  112. lexpr.reverse()
  113. except ValueError:
  114. pass
  115.  
  116. res = calculadora_prefija_iterativa(lexpr)
  117. print(expr, "=", res)
  118. else:
  119. print("Expr. incorrecta")
  120.  
Success #stdin #stdout 0.03s 9036KB
stdin
+ 5 * 6 7
stdout
Dame un expr.: + 5 * 6 7 = 47.0