How will I convert decimals into accurate fractions or accurate decimals? - python

For some reason it shows an error message: TypeError: argument should be a string or a Rational instance
import cmath
from fractions import Fraction
#Function
# Quadratic equatrion solver
def solver(a_entry, b_entry, c_entry):
a = int(a_entry)
b = int(b_entry)
c = int(c_entry)
d = (b*b) - (4*a*c)
sol1 = (-b-cmath.sqrt(d)/(2*a))
sol2 = (-b+cmath.sqrt(d)/(2*a))
sol3 = Fraction(sol1)
sol4 = Fraction(sol2)
print(f"Value of x1 = {sol3} and value of x2 = {sol4}")
solver(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in solver
File "/usr/lib/python3.10/fractions.py", line 139, in __new__
raise TypeError("argument should be a string "
TypeError: argument should be a string or a Rational instance
I am a new programmer and I saw that this code generates a weird number (example: 5.42043240824+0j {inaccurate values})
when i give random values. So I want it to give either an accurate decimal values or in fraction. The fraction method dosen't work for some reason. Can someone please help. Alot of thanks.

2 things wrong in your code :
Use math instead of cmath as cmath is used for complexed values (it will always returns a complexe value, even 1+0j) which is not compatible with Fraction.
Be careful you wrote : (-b-cmath.sqrt(d)/(2*a)) but is should be ((-b-cmath.sqrt(d))/(2*a))
Also, the solution might no exist. For example, resolving 1x^2 + 3x + 10 has no answer (your fonction does not cross x axe). It still has complexe answer(s).
To avoid this you can use a try except to catch errors. OR you can validate that d^2 is greater than 4ac because you can't sqrt negative values (except with complexe values ;) ) :
def solver():
a = int(entry.get())
b = int(entry1.get())
c = int(entry2.get())
d = (b*b) - (4*a*c)
if d < 0:
text = "no real answer ! The function doesn't cross X axe !"
label2.configure(text = text)
else:
sol1 = ((-b-math.sqrt(d))/(2*a))
sol2 = ((-b+math.sqrt(d))/(2*a))
sol3 = Fraction(sol1)
sol4 = Fraction(sol2)
label2.configure(text = f"Value of x1 = {sol3} and value of x2 = {sol4}")
Hope it helps

The issue with sqrt
It appears that you do not want to evaluate the square roots to numerical approximations. But that is exactly what cmath.sqrt and math.sqrt do: they calculate numerical approximations of square roots.
For instance:
import math
print( math.sqrt(2) )
# 1.4142135623730951
If you are not interested in numerical approximations, then I suggest using a library for symbolic calculus. The best-known library for symbolic calculus in python is called sympy. This module has a sympy.sqrt function that will simplify a square root as much as it can, but without returning a numerical approximation:
import sympy
print( sympy.sqrt(9) )
# 3
print( sympy.sqrt(2) )
# sqrt(2)
print( sympy.sqrt(18) )
# 3*sqrt(2)
More information about sympy: https://docs.sympy.org/latest/tutorials/intro-tutorial/intro.html
Other advice
When you write a program, it is most usually a good idea to cleanly separate the parts of the code that deal with algorithms, maths, and logic, from the parts of the code that deal with input and output. I suggest writing two functions, one that solves quadratic equations, and one that does input and output:
import sympy
# returns solutions of a x**2 + b x + c == 0
def solver(a, b, c):
Delta = b*b - 4*a*c
sol1 = (-b - sympy.sqrt(Delta)) / (2*a)
sol2 = (-b + sympy.sqrt(Delta)) / (2*a)
return (sol1, sol2)
# ask for user input and solve an equation
def input_equation_output_solution():
a = int(entry.get())
b = int(entry1.get())
c = int(entry2.get())
sol1, sol2 = solver(a, b, c)
label2.configure(text = f"Value of x1 = {sol1} and value of x2 = {sol2}")

Related

evalf and subs in sympy on single variable expression returns expression instead of expected float value

I'm new to sympy and I'm trying to use it to get the values of higher order Greeks of options (basically higher order derivatives). My goal is to do a Taylor series expansion. The function in question is the first derivative.
f(x) = N(d1)
N(d1) is the P(X <= d1) of a standard normal distribution. d1 in turn is another function of x (x in this case is the price of the stock to anybody who's interested).
d1 = (np.log(x/100) + (0.01 + 0.5*0.11**2)*0.5)/(0.11*np.sqrt(0.5))
As you can see, d1 is a function of only x. This is what I have tried so far.
import sympy as sp
from math import pi
from sympy.stats import Normal,P
x = sp.symbols('x')
u = (sp.log(x/100) + (0.01 + 0.5*0.11**2)*0.5)/(0.11*np.sqrt(0.5))
N = Normal('N',0,1)
f = sp.simplify(P(N <= u))
print(f.evalf(subs={x:100})) # This should be 0.5155
f1 = sp.simplify(sp.diff(f,x))
f1.evalf(subs={x:100}) # This should also return a float value
The last line of code however returns an expression, not a float value as I expected like in the case with f. I feel like I'm making a very simple mistake but I can't find out why. I'd appreciate any help.
Thanks.
If you define x with positive=True (which is implied by the log in the definition of u assuming u is real which is implied by the definition of f) it looks like you get almost the expected result (also using f1.subs({x:100}) in the version without the positive x assumption shows the trouble is with unevaluated polar_lift(0) terms):
import sympy as sp
from sympy.stats import Normal, P
x = sp.symbols('x', positive=True)
u = (sp.log(x/100) + (0.01 + 0.5*0.11**2)*0.5)/(0.11*sp.sqrt(0.5)) # changed np to sp
N = Normal('N',0,1)
f = sp.simplify(P(N <= u))
print(f.evalf(subs={x:100})) # 0.541087287864516
f1 = sp.simplify(sp.diff(f,x))
print(f1.evalf(subs={x:100})) # 0.0510177033783834

Solving for Zeros of a Sturm Liouville Problem in Sympy

I'm trying to solve for the zeros of a Sturm Liouville problem in sympy
here is my code
from sympy import *
init_printing(use_latex='mathjax')
# Function Definitions
u = Function('u')
X = Function('X')
# Variables and Dummies
x = Dummy('x')
mu = Symbol('mu', nonzero=True, positive=True)
C1 = Symbol('C1', nonzero=True)
C2 = Symbol('C2', nonzero=True)
print("STURM LIOUVILLE PROBLEM IN X")
print("GENERAL SOLUTION")
# --- --- ---#
print("")
gen_sol = dsolve(Eq(Derivative(X(x), x, 2) + (mu**2)*X(x), 0), X(x))
print(pretty(gen_sol))
print("")
print("SOLVE FOR BOUNDARY")
bc_2 = gen_sol.rhs.diff(x).subs(x,5).subs(Symbol('C1')*mu, Symbol('C2'))
print("DETERMINE THAT C2 != 0 (NON TRIVIAL)")
print(pretty(bc_2))
print("")
print("SOLVE FOR REMAINING SOLUTION")
bc_2 = bc_2.subs(Symbol('C2'), 1)
print(pretty(bc_2))
print("")
linear_solutions = solve([bc_2], [mu])
print(pretty(linear_solutions))
Unfortunatly I get the following NotImplemented Error.
Is there anther way to solve for zeros in sympy that can handle this operation?
STURM LIOUVILLE PROBLEM IN X
GENERAL SOLUTION
X(x) = C₁⋅sin(x⋅μ) + C₂⋅cos(x⋅μ)
SOLVE FOR BOUNDARY
DETERMINE THAT C2 != 0 (NON TRIVIAL)
-C₂⋅μ⋅sin(5⋅μ) + C₂⋅cos(5⋅μ)
SOLVE FOR REMAINING SOLUTION
-μ⋅sin(5⋅μ) + cos(5⋅μ)
Traceback (most recent call last):
File "stack_overflow.py", line 31, in <module>
linear_solutions = solve([bc_2], [mu])
File "/home/cgould/.local/lib/python3.8/site-packages/sympy/solvers/solvers.py", line 1176, in solve
solution = _solve_system(f, symbols, **flags)
File "/home/cgould/.local/lib/python3.8/site-packages/sympy/solvers/solvers.py", line 1943, in _solve_system
raise NotImplementedError('could not solve %s' % eq2)
(EDIT FOR CLARITY)
The idea here, is that I'm trying to find the zeros of the below
-μ⋅sin(5⋅μ) + cos(5⋅μ) = 0
which roughly translates to:
cot(5μ) = μ
solve will only solve an equation for which a closed-form solution has been programmed, giving an exact symbolic solution. nsolve will find a numerical approximation:
>>> μ = mu
>>> nsolve(-μ*sin(5*μ) + cos(5*μ), 0)
0.262767543298580
Since your equation has multiple roots, you will have to use a different initial guess to get a different solution (or use the bisection method and give the region in which you want to find a root). A nice way to do this is to find the first two roots and then use the difference between them as a guess for the distance to the next root: the first order continuation method.
>>> r = []
>>> r.append(nsolve(-μ*sin(5*μ) + cos(5*μ),0))
>>> r.append(nsolve(-μ*sin(5*μ) + cos(5*μ),.5))
>>> for i in range(5):
... r.append(nsolve(-μ*sin(5*μ) + cos(5*μ),2*r[-1] - r[-2]))
...
>>> [i.round(2) for i in r]
[0.26, 0.81, 1.38, 1.98, 2.59, 3.20, 3.82]

How to avoid math domain error when we have sqrt

I wrote the following code, after printing about 10 outputs it gets error
return 1/sqrt(Om*(1+z)**3+omg0*(1+z)**6+(1-Om-omg0))
ValueError: math domain error
the three first functions are correct and work well in other programs please do not be sensitive about their structures, I think the problem is in for-loop and choosing some values which cannot satisfy the condition of sqrt. Could I add some lines to tell Python avoid numbers which lead to math domain error? If yes, How should I do that? I mean passing the step which leads to negative value under sqrt?
Cov is a 31*31 mtrix, xx[n] is a list of 31 numbers.
def ant(z,Om,w):
return 1/sqrt(Om*(1+z)**3+w*(1+z)**6+(1-Om-w))
def dl(n,Om,w,M):
q=quad(ant,0,xx[n],args=(Om,w))[0]
h=5*log10((1+xx[n])*q)
fn=(yy[n]-M-h)
return fn
def c(Om,w,M):
f_list = []
for i in range(31): # the value '2' reflects matrix size
f_list.append(dl(i,Om,w,M))
A=[f_list]
B=[[f] for f in f_list]
C=np.dot(A,Cov)
D=np.dot(C,B)
F=np.linalg.det(D)*0.000001
return F
N=100
for i in range (1,N):
R3=np.random.uniform(0,1)
Omn[i]=Omo[i-1]+0.05*np.random.normal()
wn[i]=wo[i-1]+0.05*np.random.normal()
Mn[i]=Mo[i-1]+0.1*np.random.normal()
L=exp(-0.5*(c(Omn[i],wn[i],Mn[i])-c(Omo[i-1],wo[i-1],Mo[i-1])))
if L>R3:
wo[i]=wn[i]
else:
wo[i]=wo[i-1]
print(wo[i])
The output is:
0.12059556415714912
0.16292726528216397
0.16644447885609648
0.1067588804671105
0.0321446951572128
0.0321446951572128
0.013169965429457382
Traceback (most recent call last):
......
return 1/sqrt(Om*(1+z)**3+omg0*(1+z)**6+(1-Om-omg0))
ValueError: math domain error
Here are some options:
Replace sqrt(...) with (...)**0.5. This will produce complex numbers, which may or may not be acceptable. For example (-1)**0.5 produces i which in Python will appear as 1j (ignoring floating point errors).
Catch errors and move on. Since you probably want to catch the errors higher up, I recommend translating the ValueError from sqrt into a custom error:
class SqrtError(ValueError):
pass
def ant(z, Om, w):
val = Om * (1 + z) ** 3 + w * (1 + z) ** 6 + (1 - Om - w)
try:
sq = sqrt(val)
except ValueError:
raise SqrtError
return 1 / sq
Then it sounds like you want to keep trying new random numbers until you get one that works, which could be done like so:
for i in range(1, N):
R3 = np.random.uniform(0, 1)
while True:
Omn[i] = Omo[i - 1] + 0.05 * np.random.normal()
wn[i] = wo[i - 1] + 0.05 * np.random.normal()
Mn[i] = Mo[i - 1] + 0.1 * np.random.normal()
try:
L = exp(-0.5 * (c(Omn[i], wn[i], Mn[i]) - c(Omo[i - 1], wo[i - 1], Mo[i - 1])))
except SqrtError:
continue
else:
break
if L > R3:
wo[i] = wn[i]
else:
wo[i] = wo[i - 1]
Your code is trying to find the square root of a negative number.
This is not allowed with real-valued numbers (for obvious mathematical reasons), so your best bet is to use a try/except block:
def ant(z,Om,w):
try:
return 1/sqrt(Om*(1+z)**3+omg0*(1+z)**6+(1-Om-omg0))
except ValueError:
return None

How to Define a Piecewise Function in Python with Multiple Variables

I am trying to develop a plot for my helioseismology class and the question had provided a piecewise function describing the dynamics of the "fluids" in a star as if it is one thing its this and if its another its that. I am receiving over and over again this 'Mul' object cannot be interpreted as an integer but I am working with numbers in the reals not just the integer set. I do not know how to get around this and need guidance. The code is as follows.
import sympy as sy
from sympy import *
from sympy.physics.units import Unit
import numpy as np
import sys
import math
import scipy as sp
from scipy import special
phi = Symbol('phi', Variable = True)
x = Symbol('x', Variable = True, Real = True)
t = Symbol('t', Variable = True, Real = True)
xi = Symbol('xi', Function = True)
Solar_Radius = Symbol('R', Constant = True, unit = "meters")
Sound_Speed = Symbol('c', Constant = True, unit = "meters per second", Real = True)
gamma = Symbol('gamma', Constant = True)
gravity = Symbol('g', Constant = True, unit = "meters per second per second")
Solar_Radius = 6.963 * 10 ** 6
gamma = 5/3
g = 274.8265625336
gas_constant = 8201.25
c = 8.1 * 10 ** 3
for t in range(0,x/c):
xi[x,t] = 0
for t in range(x/c,00):
xi[x,t] = (1/2)*sy.exp(gamma*g*x/(2*c**2))*mpmath.besselj(0, (gamma*g/(2*c)*sy.sqrt(t**2 - ((x/c)**2))),derivative = 0)
Full Traceback:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-50-3506376f1686> in <module>()
----> 1 for t in range(0,x/c):
2 xi[x,t] = 0
3 for t in range(x/c,00):
4 xi[x,t] = (1/2)*sy.exp(gamma*g*x/(2*c**2))*mpmath.besselj(0, (gamma*g/(2*c)*sy.sqrt(t**2 - ((x/c)**2))),derivative = 0)
TypeError: 'Mul' object cannot be interpreted as an integer
There are quite a few issues here:
None of the keyword arguments (Constant, Variable, unit, Real) that you are passing to Symbol are things that are recognized by SymPy. The only one that is close is real, which should be lowercase (like Symbol('x', real=True)). The rest do nothing. If you want units, you should use the SymPy units module in sympy.physics.units. There is no need to specify if a symbol is constant or variable.
You have redefined Solar_Radius and gamma as numbers. That means that the Symbol definitions for those variables are pointless.
If you are using Python 2, make sure to include from __future__ import division at the top of the file, or else things like 1/2 and 5/3 will be truncated with integer division (this isn't an issue in Python 3).
range(0, x/c) doesn't make sense. range creates a list of numbers, like range(0, 3) -> [0, 1, 2]. But x/c is not a number, it's a symbolic expression.
Additionally, xi[x, t] = ... doesn't make sense. xi is a Symbol, which doesn't allow indexing and certainly doesn't allow assignment.
Don't mix numeric (math, mpmath, numpy, scipy) functions with SymPy functions. They won't work with symbolic expressions. You should use only SymPy functions. If you create a symbolic expression and want to convert it to a numeric one (e.g., for plotting), use lambdify.
What you want here is Piecewise. The syntax is Piecewise((expr, cond), (expr, cond), ..., (expr, True)), where expr is an expression that is used when cond is true ((expr, True) is the "otherwise" condition).
For your example, I believe you want
expr = Piecewise((0, t < x/c), (sy.exp(gamma*g*x/(2*c**2))*sy.besselj(0, (gamma*g/(2*c)*sy.sqrt(t**2 - (x/c)**2)))/2, t >= x/c))
If you want to turn this into a numeric function in x and t, use
xi = lambdify((x, t), expr)

Writing a function for x * sin(3/x) in python

I have to write a function, s(x) = x * sin(3/x) in python that is capable of taking single values or vectors/arrays, but I'm having a little trouble handling the cases when x is zero (or has an element that's zero). This is what I have so far:
def s(x):
result = zeros(size(x))
for a in range(0,size(x)):
if (x[a] == 0):
result[a] = 0
else:
result[a] = float(x[a] * sin(3.0/x[a]))
return result
Which...doesn't work for x = 0. And it's kinda messy. Even worse, I'm unable to use sympy's integrate function on it, or use it in my own simpson/trapezoidal rule code. Any ideas?
When I use integrate() on this function, I get the following error message: "Symbol" object does not support indexing.
This takes about 30 seconds per integrate call:
import sympy as sp
x = sp.Symbol('x')
int2 = sp.integrate(x*sp.sin(3./x),(x,0.000001,2)).evalf(8)
print int2
int1 = sp.integrate(x*sp.sin(3./x),(x,0,2)).evalf(8)
print int1
The results are:
1.0996940
-4.5*Si(zoo) + 8.1682775
Clearly you want to start the integration from a small positive number to avoid the problem at x = 0.
You can also assign x*sin(3./x) to a variable, e.g.:
s = x*sin(3./x)
int1 = sp.integrate(s, (x, 0.00001, 2))
My original answer using scipy to compute the integral:
import scipy.integrate
import math
def s(x):
if abs(x) < 0.00001:
return 0
else:
return x*math.sin(3.0/x)
s_exact = scipy.integrate.quad(s, 0, 2)
print s_exact
See the scipy docs for more integration options.
If you want to use SymPy's integrate, you need a symbolic function. A wrong value at a point doesn't really matter for integration (at least mathematically), so you shouldn't worry about it.
It seems there is a bug in SymPy that gives an answer in terms of zoo at 0, because it isn't using limit correctly. You'll need to compute the limits manually. For example, the integral from 0 to 1:
In [14]: res = integrate(x*sin(3/x), x)
In [15]: ans = limit(res, x, 1) - limit(res, x, 0)
In [16]: ans
Out[16]:
9⋅π 3⋅cos(3) sin(3) 9⋅Si(3)
- ─── + ──────── + ────── + ───────
4 2 2 2
In [17]: ans.evalf()
Out[17]: -0.164075835450162

Categories

Resources