10

I have an expression from a sympy calculation:

sqrt(pi)*(0.333333333333333*a + 0.333333333333333*b - 2.66666666666667*c**2)

where a,b,c are symbols, and would like to parse it so that the floats are replaced with rationals like in

sqrt(pi)*(1/3*a + 1/3*b - 8/3*c**2)

I know how to do one by hand,

In[24] Rational(str(0.333333333333333)).limit_denominator(1000)

Out[24]: 1/3

but do not quite know how to go about parsing the atoms and picking only the ones that are floats, and substituting back the rational number approximation.

What is the smartest way of doing these substitutions in the expression?

acortis
  • 400
  • 3
  • 15

2 Answers2

16

Use nsimplify:

>>> print(nsimplify(sqrt(pi)*(0.333333333333333*a + 0.333333333333333*b - 2.66666666666667*c**2)))
sqrt(pi)*(a/3 + b/3 - 8*c**2/3)
asmeurer
  • 86,894
  • 26
  • 169
  • 240
3

After a bit of fiddling, I think I have found a way to do it, but I am not sure that it will cover all the corner cases. At any rate here it is. Any suggestions for improvement?

import sympy
def rationalize_coeffs(expr):
    for i in expr.atoms(sympy.Float):
        r = sympy.Rational(str(i)).limit_denominator(1000)
        expr = expr.subs(i, r)
    return expr    

if __name__=='__main__':
    # given a sympy expression expr
    x,y,z = sympy.symbols('x y z')
    # expr_orig = 2/57.*x + 3./4.*y + 3./4.*z
    expr = 0.0350877192982456*x + 0.75*y + 0.75*z

    print rationalize_coeffs(expr)
acortis
  • 400
  • 3
  • 15
  • 2
    Don't use strings. And anyway `r` is already a rational number, so `expr.subs(i, r)` should do what you want. – asmeurer Jan 12 '14 at 01:43