Search code examples
pythoneval

How to prevent errors with large results when using eval()?


I'm making a calculator in Python and am currently trying to prevent the program crashing when dealing with large input.

The only way I know how to catch errors is using 'try' and 'except', so I wrote this:

def solve(self, equation):
    try:
        return eval(equation)
    except(OverflowError):
        messagebox.showinfo("Error","Result too large")
    return equation

(I'm aware eval can be dangerous but the user is unable to type any input so I think it's fine)

When I input a massive number in scientific notation like '389e+10**(58)*9' the OverflowError is caught successfully, but if I put in something like '55555555**5555555' the window stops responding.

I was under the impression the latter also raises an OverflowError but I now I think this is could be happening because it doesn't create an error at all, and eval just can't handle working out a result this large.

If this is the case, I think I should put a limit on how large the answer should be, but I'm unsure of how I would decide on this limit. Any suggestions?


Solution

  • In Python, float is usually a 64-bit floating point number, which can hold a finite range. Values above that cause an OverflowError to be raised. As 389e+10 returns a float, the entire expression 389e+10**(58)*9 also returns a float.

    On the other hand, 55555555**5555555 returns an int. In Python, int can hold arbitrarily large values, limited only by memory. Therefore, what is happening is that Python attempts to calculate a really big number, taking a really, really long time to do so.

    This is, in general, not that easy of a question to solve, because you're using eval, and therefore you have no information about the exact nature of the equation.

    I would suggest instead parsing the equation, which will allow you to inspect it in detail. You could then, among other things, not perform exponentiation calculations where both the base and exponent are large.

    (or you could just use floating point calculation for everything, which will affect precision, but I don't think that really matters for a simple calculator, right?)