sloan
sloan

Reputation: 329

Replace '**' with 'math.pow' in Python

I have some mathematical functions (represented as strings) in a file:

1+a**(b/(3*a+1))
(1+a)**(b/(3*a+1))
...

How can I transform all **s in my string to math.pow?

Edit: What I'm trying to solve is the following : I've a lot of this functions to evaluate, I can't spend too much time on one.

Sometimes functions look like that :

(3**100**100**2)

Python try to evaluate it, which is very long. I would like to have an error instead like :

>>> math.pow(3, math.pow(100, 100))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: math range error

Edit 2 : Thanx all for answering, I finally found how to do it, and your answers and comments helped me a lot. I just had to force float division with next line at the top of my file :

      from __future__ import division

Upvotes: 2

Views: 1409

Answers (2)

Eric
Eric

Reputation: 97601

What you seem to be trying to avoid here is long integer arithmetic, which can take an arbitrarily large amount of time to execute. The easiest way to fix this is:

class Floatify(ast.NodeTransformer):
    def visit_Num(self, node):
        return ast.Num(float(node.n))

Which when used:

>>> node = ast.parse("(3**100**100**2)", mode="eval")
>>> node = Floatify().visit(node)
>>> code = compile(node, "<string>", mode="eval")
>>> eval(code)

Traceback (most recent call last):
  File "<pyshell#14>", line 1, in <module>
    eval(code)
  File "<string>", line 1, in <module>
OverflowError: (34, 'Result too large')

Upvotes: 0

filmor
filmor

Reputation: 32222

You can use the following transformer:

import ast

pow_func = ast.parse("math.pow", mode="eval").body

class PowForDoubleStar(ast.NodeTransformer):
    def visit_BinOp(self, node):
        node.left = self.visit(node.left)
        node.right = self.visit(node.right)

        if isinstance(node.op, ast.Pow):
            node = ast.copy_location(
                       ast.Call(func=pow_func,
                                args=[node.left, node.right],
                                keywords=[]
                               ),
                       node
                   )

        return node

In your particular example you can execute those code parts using

for line in file:
    node = ast.parse(line, mode="eval")
    node = PowForDoubleStar().visit(node)
    code = compile(node, "<string>", mode="eval")
    a, b = 1, 3
    result = eval(code)

Upvotes: 3

Related Questions