Problem
- your assumption that the solution is real in combination with a poor sympys score for numerical uncertainty. If you select a task, you will receive the following code:
import sympy as sym def H_I(P): return (-941.254840173) + (0.014460465765)*P + (-9.41529726451e-05)*P**2 + (1.23485231253e-06)*P**3 def H_II(P): return (-941.254313412) + (0.014234188877)*P + (-0.00013455013645)*P**2 + (2.58697027372e-06)*P**3 P = sym.symbols('P') sol = sym.solve(H_I(P) - H_II(P) , P) sol = [x.evalf() for x in sol] print(sol)
with output:
[- 6.32436145176552 + 1.0842021724855e-19 * I, 1.79012202335501 + 1.0842021724855e-19 * I, 34.4111917095165 - 1.35525271560688e-20 * I]
You can access the real part of the sym.re(x) solution
Decision
If you have a certain numerical accuracy, I think the easiest way to collect your real results is something similar to this piece of code:
def is_close(a,b,tol): if abs(ab)<tol: return True else: return False P = sym.symbols('P') sol = sym.solve(H_I(P) - H_II(P) , P) sol = [complex(x.evalf()) for x in sol] real_solutions = [] for x in sol: if is_close(x,x.real,10**(-10)): real_solutions.append(x.real) print(real_solutions)
Because you asked: I use a difficult question of taste. Not necessary, depending on your future goal. However, there are no restrictions. I am writing this is_close () as a function for general reasons. You can use this code for other polynomials or use this function in a different context, so why not write the code in an intelligent and understandable way? However, the initial goal is to tell me if the variable x and its real part re (x) are the same up to a certain numerical accuracy, i.e. The imaginary part is negligible. You should also check out the minor real parts that I forgot.
Edit
The small imaginary parts are usually residues of subtractions on complex numbers that occur somewhere in the process of solving. Perceived to be accurate, sympy does not erase them. evalf () gives you a numerical estimate or approximation of an exact solution. This is not about the best accuracy. Consider, for example:
import sympy as sym def square(P): return P**2-2 P = sym.symbols('P') sol2 = sym.solve(square(P),P) print(sol2)
This code prints:
[- sqrt (2), sqrt (2)]
not a floating point number as you might expect. The solution is accurate and perfectly accurate. However, this, in my opinion, is not suitable for further calculations. Therefore, I use evalf () for every sympy result. If you use a numerical estimate for all the results in this example, the output will look like this:
[- 1.41421356237310, 1.41421356237310]
Why is it not suitable for further calculations, you may ask? Remember your first code. The first root found was
-6.32436145176552 + 0.e-19 * I
Yes, the imaginary part is zero, nice. However, if you print sym.im(x) == 0 , the output is False . Computers and the operator "precise" are sensitive combinations. Be careful.
Decision 2
If you want to get rid of only a small imaginary part without imposing explicit quantitative accuracy, you can simply use the .evalf(chop = True) keyword inside the numerical estimate. This effectively neglects unnecessary small numbers and simply cuts off the imaginary part in your source code. Given that you are even well versed in any imaginary parts, as you stated in your answer, this is probably the best solution for you. For completeness reasons, here is the corresponding code
P = sym.symbols('P') sol = sym.solve(H_I(P) - H_II(P) , P) sol = [x.evalf(chop=True) for x in sol]
But remember that this is not so different from my first approach, if you also implemented βclippingβ for the real part. However, the difference is this: you have no idea about the accuracy that this imposes. If you never work with other polynomials, this may be good. The following code should highlight the problem:
def H_0(P): return P**2 - 10**(-40) P = sym.symbols('P') sol = sym.solve(H_0(P) , P) sol_full = [x.evalf() for x in sol] sol_chop = [x.evalf(chop=True) for x in sol] print(sol_full) print(sol_chop)
Even though your roots are perfectly beautiful and still accurate after using evalf (), they are chopped off because they are too small. That is why I would advise with the simplest, most general solution of all time. After that, look at your polynomials and find out about the required numerical accuracy.