首页 > 解决方案 > 当涉及非常大的计算时,如何编写程序以显示“太大的结果”?

问题描述

我尝试在图形计算器中计算 32**(32**32),但程序挂起。如何像字符串一样显示“太大的结果”而不是挂起?
我使用了以下功能。

def result(text):
    global backend, frontend, backend_list, frontend_list
    try:
        backend_list.append(str(eval(backend)))
        backend=backend_list[-1]
        frontend_list.append(str(round(eval(backend),5)))
        frontend=frontend_list[-1]
        backend_list.clear()
        backend_list.append(backend)
        frontend_list.clear()
        frontend_list.append(frontend)
        text.delete(1.0, END)
        text.insert(INSERT, frontend)
    except ZeroDivisionError:
        backend=frontend=""
        text.delete(1.0, END)
        text.insert(INSERT, "not defined")
    except TypeError:
        backend=frontend=""
        text.delete(1.0, END)
        text.insert(INSERT, "type error: presumably\ncomplex number or\nmissing operators")
    except:
        text.delete(1.0, END)
        text.insert(INSERT, "error")

标签: python

解决方案


python 这样做的问题是 python 在技术上没有整数的大小限制。最终,您的计算机将在尝试计算时耗尽内存,但这需要一段时间,并且计算机将挂起,直到它完成为止。

与整数不同,浮点数有大小限制。如果需要,您可以将参数转换为浮点数并依靠内置的浮点行为为您完成工作:

try:
    eval('float(32) ** 32 ** 32')
except OverflowError:
    print("Result too large")

问题在于您依赖eval(),这使您无法控制。如果您希望您的计算器真正灵活,您必须自己解码和解释表达式。ast或 'Abstract Syntax Tree'是最好的方法,您可以使用 和 的组合来逐个遍历操作数并根据需要对其进行评估ast.parse(your_input)ast.walk(result_of_parse)这会很复杂,您需要仔细考虑如何实现它,但一个简单的解决方案可能是遍历树并将所有常量转换为浮点数,如果它们还没有的话:

import ast

...

def eval_ast(expr='32 ** 32 ** 32'):
    # decompose into parsed elements
    # if entered normally, expr() will be a hierarchy of AST objects. The top few
    # are not useful to us:
    #    ast.Module     (has attribute .body containing a list of the next level)
    #    ast.Expr       (has attribute .value containing the next level)
    # so we attempt to ignore them.
    expr_obj = ast.Expression(ast.parse(expr).body[0].value)
    # walk through the nodes in the AST and convert integers to floats
    for node in ast.walk(expr_obj):
        if isinstance(node, ast.Constant):
            node.value = float(node.value)
    # recompose back into an evaluatable expression
    expr_eval = ast.fix_missing_locations(expr_obj)
    exe = compile(expr_eval, filename="<string>", mode="eval")
    return eval(exe)

如所写,这将引发“结果太大”错误。如果使用不同的表达式调用,不会溢出,它将正确返回结果:

>>> eval_ast('32 ** 32 ** 32')
Traceback (most recent call last):
  ...
OverflowError: (34, 'Result too large')
>>> eval_ast('2 ** 32')
4294967296.0

您可以自定义它并根据需要将其集成到您的计算器中。如果您需要更精确或更精细的控制,手动遍历 AST 表达式并自己评估每个步骤可能对您更有用。


推荐阅读