SymPy, how to perform exact symbolic representation (Rational Issue)? - python

So I'm planning to write a web application about math, and I need to convert user input to a SymPy expression without modifying it (Simplification), eg. so I'd like to cancel this behaviour like in this example.
>>> srepr(Rational(2,4)) #this is the problem
'Rational(1, 2)'
>>> srepr(Rational(2,4,evaluate=False)) #doesn't work
Traceback...
But I've managed to do it in other types of representations.
>>> srepr(Pow(x,(Mul(e,e,evaluate=False)),evaluate=False)) #nice
"Pow(Symbol('x'), Mul(Symbol('e'), Symbol('e')))"
>>> srepr(sqrt(Integer(8))) #not what I want
'Mul(Integer(2), Pow(Integer(2), Rational(1, 2)))'
>>> srepr(Pow(Integer(8),Rational(1,2),evaluate=False)) #this is the way
'Pow(Integer(8), Rational(1, 2))'
>>> from sympy import E
>>> log(E,evaluate=False)
log(E)
Also isn't there a way to tell SymPy that all representations shouldn't be evaluated?

Something like this, perhaps?
>>> S('2/4',evaluate=False)
2/4
>>> srepr(_)
'Mul(Integer(2), Pow(Integer(4), Integer(-1)))'

Related

How to simplify a sympy expression

Hello I have this sympy expression 0.5*c**2*m*(v/c)**2.0 and I want to bring it automatically to this form: 0.5*m*v**2. I tried the sympy simplify function but that doesn't seem to work. What can I do? Thank you!
These two expressions are not equivalent, only equivalent if c is not equal to 0. So if you want to get 0.5*m*v**2, you need set c as a positive number:``
>>> import sympy
>>> c= sympy.symbols('c',positive=True)
>>> m,v = sympy.symbols('m v')
>>> sympy.powsimp(0.5*c**2*m*(v/c)**2.0)
0.5*m*v**2.0
Besides, although sympy.simplify will give you what you want, I think sympy.powsimp is better. Because actually we want to reduce expression by combining powers with similar bases and exponents.

Calculating strings as values

Is it possible in Python to calculate a term in a string?
For example:
string_a = "4 ** (3 - 2)"
unknown_function(string_a) = 4
Is this possible? Is there a function that mimics "unknown_function" in my example?
Just like sympy was a useful module for your last question, it can apply here:
>>> import sympy
>>> sympy.sympify("4**(3-2)")
4
and even
>>> sympy.sympify("2*x+y")
2*x + y
>>> sympy.sympify("2*x+y").subs(dict(x=2, y=3))
7
Note though that this will return sympy objects, and if you want to get an integer or a float out of it you should do the conversion explicitly:
>>> type(sympy.sympify("4**(3-2)"))
<class 'sympy.core.numbers.Integer'>
>>> int(sympy.sympify("4**(3-2)"))
4
I hacked together a recipe to turn string expressions into functions here which is kind of cute.
There is eval
eval(string_a)
# 4
But do not use this under any circumstances if string_a comes from anyone but you, because they can easily hack into your system and destroy your files!
Yes, you can use the eval function.
>>> string_a = "4 ** (3 - 2)"
>>> eval(string_a)
4
>>>
You can read more in the documentation
There is a module py-expression-eval, that does not depend on the use of eval. It can be used to evaluate strings as a mathematical expression, even symbolic expressions can be evaluated.
from py_expression_eval import Parser
parser = Parser()
expr = parser.parse("4 ^ (3 - 2)")
expr.evaluate({})
For the use with symbolic expressions see:https://axiacore.com/blog/mathematical-expression-evaluator-python/

"rounding" a negative exponential in python

I am looking to convert some small numbers to a simple, readable output. Here is my method but I wondering if there is something simpler.
x = 8.54768039530728989343156856E-58
y = str(x)
print "{0}.e{1}".format(y.split(".")[0], y.split("e")[1])
8.e-58
This gets you pretty close, do you need 8.e-58 exactly or are you just trying to shorten it into something readable?
>>> x = 8.54768039530728989343156856E-58
>>> print "{0:.1e}".format(x)
8.5e-58
An alternative:
>>> print "{0:.0e}".format(x)
9e-58
Note that on Python 2.7 or 3.1+, you can omit the first zero which indicates the position, so it would be something like "{:.1e}".format(x)
like this?
>>> x = 8.54768039530728989343156856E-58
>>> "{:.1e}".format(x)
'8.5e-58'
Another way of doing it, if you ever want to extract the exponent without doing string manipulations.
def frexp_10(decimal):
logdecimal = math.log10(decimal)
return 10 ** (logdecimal - int(logdecimal)), int(logdecimal)
>>> frexp_10(x)
(0.85476803953073244, -57)
Format as you wish...
There are two answers: one for using the number and one for simple display.
For actual numbers:
>>> round(3.1415,2)
3.14
>>> round(1.2345678e-10, 12)
1.23e-10
The built-in round() function will round a number to an arbitrary number of decimal places. You might use this to truncate insignificant digits from readings.
For display, it matters which version of display you use. In Python 2.x, and deprecated in 3.x, you can use the 'e' formatter.
>>> print "%6.2e" % 1.2345678e-10
1.23e-10
or in 3.x, use:
>>> print("{:12.2e}".format(3.1415))
3.14e+00
>>> print("{:12.2e}".format(1.23456789e-10))
1.23e-10
or, if you like the zeros:
>>> print("{:18.14f}".format(1.23456789e-10))
0.00000000012346

How can I change what python interprets as a integer?

How can I change what python interprets as a integer? For example: 94*n would be a valid integer.
Anything is possible when you smell like Old Spice and use Python's language services to generate a AST.
On the off chance that you're not trying to modify Python's grammar, you could use int():
>>> n = 1.2
>>> x = 94*n
>>> type(x)
<type 'float'>
>>> y = int(94*n) # use int()
>>> type(y)
<type 'int'>
You can use int() and float() to convert numeric types. If you want a computer algebra system in Python, then you may be interested in taking a look at sympy which lets you do something like:
from sympy import *
n = Symbol('n')
x = 94*n
print x
print x.subs(n, 5)
If you are trying to write a computer algebra system, I would recommend using Sympy if it meets your needs or contributing to Sympy to enhance it rather than creating a whole new system from scratch.

Converting a float to a string without rounding it

I'm making a program that, for reasons not needed to be explained, requires a float to be converted into a string to be counted with len(). However, str(float(x)) results in x being rounded when converted to a string, which throws the entire thing off. Does anyone know of a fix for it?
Here's the code being used if you want to know:
len(str(float(x)/3))
Some form of rounding is often unavoidable when dealing with floating point numbers. This is because numbers that you can express exactly in base 10 cannot always be expressed exactly in base 2 (which your computer uses).
For example:
>>> .1
0.10000000000000001
In this case, you're seeing .1 converted to a string using repr:
>>> repr(.1)
'0.10000000000000001'
I believe python chops off the last few digits when you use str() in order to work around this problem, but it's a partial workaround that doesn't substitute for understanding what's going on.
>>> str(.1)
'0.1'
I'm not sure exactly what problems "rounding" is causing you. Perhaps you would do better with string formatting as a way to more precisely control your output?
e.g.
>>> '%.5f' % .1
'0.10000'
>>> '%.5f' % .12345678
'0.12346'
Documentation here.
len(repr(float(x)/3))
However I must say that this isn't as reliable as you think.
Floats are entered/displayed as decimal numbers, but your computer (in fact, your standard C library) stores them as binary. You get some side effects from this transition:
>>> print len(repr(0.1))
19
>>> print repr(0.1)
0.10000000000000001
The explanation on why this happens is in this chapter of the python tutorial.
A solution would be to use a type that specifically tracks decimal numbers, like python's decimal.Decimal:
>>> print len(str(decimal.Decimal('0.1')))
3
Other answers already pointed out that the representation of floating numbers is a thorny issue, to say the least.
Since you don't give enough context in your question, I cannot know if the decimal module can be useful for your needs:
http://docs.python.org/library/decimal.html
Among other things you can explicitly specify the precision that you wish to obtain (from the docs):
>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')
A simple example from my prompt (python 2.6):
>>> import decimal
>>> a = decimal.Decimal('10.000000001')
>>> a
Decimal('10.000000001')
>>> print a
10.000000001
>>> b = decimal.Decimal('10.00000000000000000000000000900000002')
>>> print b
10.00000000000000000000000000900000002
>>> print str(b)
10.00000000000000000000000000900000002
>>> len(str(b/decimal.Decimal('3.0')))
29
Maybe this can help?
decimal is in python stdlib since 2.4, with additions in python 2.6.
Hope this helps,
Francesco
I know this is too late but for those who are coming here for the first time, I'd like to post a solution. I have a float value index and a string imgfile and I had the same problem as you. This is how I fixed the issue
index = 1.0
imgfile = 'data/2.jpg'
out = '%.1f,%s' % (index,imgfile)
print out
The output is
1.0,data/2.jpg
You may modify this formatting example as per your convenience.

Categories

Resources