Can't Raise negative numbers to a fractional power - python

x1 = -b + (b **2 - 4*a*c) ** 0.5
x2 = x1 / (2 * a)
My program takes user input and solves the quadratic function. However it is unable to process negative numbers, and I get the fractional power error. I want to know how to make it so that my program can accept negative numbers and still give correct answers.
I tried following but it doesn't give me an output, just blank lines:
x1 = -b + (b **2 - 4*a*c+0j) ** 0.5
x2 = x1 / (2 * a)

you should work with complex numbers for this purpose use cmath:
import cmath
x1 = -b + cmath.sqrt(b **2 - 4*a*c)
x2 = x1 / (2 * a)

Related

Python - Quadratic Equatin Extreme numbers

I have written code to solve quadratic equation in Python. But it has errors with very large numbers like "1e10" and "-1e10". Is there any solution numerically or as python solution?
enter code here
import math
import cmath
def solve_quad(b, c):
a = 1
D = b*b - 4*a*c
if (D > 0):
x1 = (-b - math.sqrt(D)) / (2*a)
x2 = (-b + math.sqrt(D)) / (2*a)
elif D == 0:
x1 = (-b - math.sqrt(D)) / (2*a)
x2 = x1
else:
x1 = (-b - cmath.sqrt(D)) / (2*a)
x2 = (-b + cmath.sqrt(D)) / (2*a)
return x1, x2
print(solve_quad(1e10, 4))
Output:
(-10000000000.0, 0.0)
This is a very old and often repeated topic. Let's explain it one more time. You use the binomial theorem to avoid numerical instability.
As the first root you chose the one where the sign of -b and the sign before the square root are the same.
if D>0:
SD = D**0.5;
if b > 0: SD = -SD
x1 = (-b+SD) / (2*a)
Then for the second root you use the formula
(-b-SD) / (2*a)
= (b^2-SD^2) / (2*a*(-b+SD))
= 4*a*c / (2*a*(-b+SD))
= (2*c) / (-b+SD)
to get
x2 = (2*c) / (-b+SD)
In the other cases the catastrophic cancellation that is avoided with this procedure does not occur.
This avoids completely all numerical instability due to catastrophic cancellation. If you want go further you can also try to avoid the potential overflow in the computation of the discriminant.
You likely have issues with floating point precision. You could use Decimal or other similar library to get better precision and circumvent this:
from decimal import *
def solve_quad(b, c):
a = 1
D = b*b - 4*a*c
if (D > 0):
x1 = (-b - D.sqrt()) / (2*a)
x2 = (-b + D.sqrt()) / (2*a)
elif D == 0:
x1 = (-b - D.sqrt()) / (2*a)
x2 = x1
else:
x1 = (-b - D.sqrt()) / (2*a)
x2 = (-b + D.sqrt()) / (2*a)
return x1, x2
print(solve_quad(Decimal(1e10), Decimal(4)))

How to solve quadratic equations with Newton-Raphson's method in Python?

Maybe I just don't understand maths. I tried different formulas but roots are really far away from correct ones.
You are given only 3 coefficients.
a = float(input())
b = float(input())
c = float(input())
x1 = -b / 2 * a + 0.0000001
x2 = -b / 2 * a - 0.0000001
for i in range(10000):
x1 = x1 - (a * x1**2 + b * x1 + c) / (2 * a * x1 + b)
x2 = x2 - (a * x2**2 + b * x2 + c) / (2 * a * x2 + b)
print(x1, x2)
You can try this one. Try changing the constants to change accuracy.

using fsolve to find the solution

import numpy as np
from scipy.optimize import fsolve
musun = 132712000000
T = 365.25 * 86400 * 2 / 3
e = 581.2392124070273
def f(x):
return ((T * musun ** 2 / (2 * np.pi)) ** (1 / 3) * np.sqrt(1 - x ** 2)
- np.sqrt(.5 * musun ** 2 / e * (1 - x ** 2)))
x = fsolve(f, 0.01)
f(x)
print x
What is wrong with this code? It seems to not work.
Because sqrt returns NaN for negative argument, your function f(x) is not calculable for all real x. I changed your function to use numpy.emath.sqrt() which can output complex values when the argument < 0, and returns the absolute value of the expression.
import numpy as np
from scipy.optimize import fsolve
sqrt = np.emath.sqrt
musun = 132712000000
T = 365.25 * 86400 * 2 / 3
e = 581.2392124070273
def f(x):
return np.abs((T * musun ** 2 / (2 * np.pi)) ** (1 / 3) * sqrt(1 - x ** 2)
- sqrt(.5 * musun ** 2 / e * (1 - x ** 2)))
x = fsolve(f, 0.01)
x, f(x)
Then you can get the right result:
(array([ 1.]), array([ 121341.22302275]))
the solution is very close to the true root, but f(x) is still very large because f(x) has a very large factor: musun.
fsolve() returns the roots of f(x) = 0 (see here).
When I plotted the values of f(x) for x in the range -1 to 1, I found that there are roots at x = -1 and x = 1. However, if x > 1 or x < -1, both of the sqrt() functions will be passed a negative argument, which causes the error invalid value encountered in sqrt.
It doesn't surprise me that fsolve() fails to find roots that are at the very ends of the valid range for the function.
I find that it is always a good idea to plot the graph of a function before trying to find its roots, as that can indicate how likely (or in this case, unlikely) it is that the roots will be found by any root-finding algorithm.

Python: interpret expression as a text and not calculate it

After a working with SyMpy library I receive an expression (in yprime variable).
from sympy import *
x = Symbol('x')
y = 1 - (0.1 * coeff1) / (x + 2) - sin(x) * (2 * x + coeff1)
yprime = y.diff(x)
Then I try to use yprime in calculations, but Python interpret it as a text: -(2*x + 1.0)*cos(x) - 2*sin(x) + 0.1/(x + 2)**2
How may I calculate -(2*x + 1.0)*cos(x) - 2*sin(x) + 0.1/(x + 2)**2 ?
After some manipulations according to mtadd:
from sympy import *
x, coeff1 = symbols('x coeff1')
y = 1 - (0.1 * coeff1) / (x + 2) - sin(x) * (2 * x + coeff1)
yprime = y.diff(x).evalf(subs={x:0,coeff1:1})
I receive a digital result, but still it's unable to operate with further logic. It says:
TypeError: can't convert expression to float
Call the method subs on your symbolic expression to calculate an analytic expression. You can call evalf on the analytic expression to a numeric solution in a Python float. Below is some example output from isympy after entering your input from above (coeff1 = 1.0).
In [18]: yprime
Out[18]:
0.1
-(2⋅x + 1.0)⋅cos(x) - 2⋅sin(x) + ────────
2
(x + 2)
In [19]: yprime.subs(x,2*pi)
Out[19]:
0.1
-4⋅π - 1.0 + ──────────
2
(2 + 2⋅π)
In [20]: yprime.subs(x,2*pi).evalf()
Out[20]: -13.5649131254944
The following program:
from sympy import *
x, C1 = symbols('x C1')
y = 1-(0.1*C1)/(x+2)-sin(x)*(2*x+C1)
print y.diff(x).evalf(subs={x:pi/2,C1:1})
prints -1.99215722345589 with sympy version 0.7.2 and python 2.7.3.
I think this might help Evaluating a mathematical expression in a string I think yprime is being interpreted as a string and this first answer of the post describes how to evaluate a string as an arithmetic expression.

Matplotlib contour isn't working

I'm trying to plot the batman equation. A solution in sympy or matplotlib will be great (sage isn't cool because I'm using windows). The problem is that if I comment out certain parts the part of the figure appears but with all the F *= parts, I get a blank plot.
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
from numpy import sqrt
from numpy import real
delta = 0.01
xrange = arange(-7.0, 7.0, delta)
yrange = arange(-3.0, 3.0, delta)
x, y = meshgrid(xrange,yrange)
F = 1
F *= (((x/7) ** 2) * sqrt(abs(abs(x) - 3)/(abs(x) - 3)) + ((y / 3) ** 2) * sqrt(abs(y + (3 * sqrt(33)) / 7)/(y + (3 * sqrt(33)) / 7)) - 1)
F *= (abs(x/2) - ((3 * sqrt(33) - 7)/112) * x**2 - 3 + sqrt(1 - (abs(abs(x) - 2) - 1) ** 2 ) - y)
F *= (9 * sqrt(abs((abs(x) - 1) * (abs(x) - 3/4))/((1 - abs(x)) * (abs(x) - 3/4))) - 8 * abs(x) - y)
F *= (3 * abs(x) + 0.75 * sqrt(abs((abs(x) - 3/4) * (abs(x) - 1/2))/((3/4 - abs(x)) * (abs(x) - 1/2))) - y)
F *= ((9/4) * sqrt(abs((x - 1/2) * (x + 1/2))/((1/2 - x) * (1/2 + x))) - y)
F *= ((6 * sqrt(10)) / 7 + (3/2 - abs(x)/2) * sqrt(abs(abs(x) - 1)/(abs(x) - 1)) - ((6 * sqrt(10))/ 14) * sqrt(4 - (abs(x) - 1) ** 2 ) - y)
G = 0
matplotlib.pyplot.contour(x, y, (F - G), [0])
matplotlib.pyplot.show()
What's going on here? If the graph is zero for one multiplicand, it should still be so no matter which other multiplicands I throw in there.
source of the batman equation: http://www.reddit.com/r/pics/comments/j2qjc/do_you_like_batman_do_you_like_math_my_math/
The parameter of sqrt is negative for many points, so the finally products are all NaN. You can plot every factor as following:
from __future__ import division # this is important, otherwise 1/2 will be 0
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
from numpy import sqrt
from numpy import real
delta = 0.01
xrange = arange(-7.0, 7.0, delta)
yrange = arange(-3.0, 3.0, delta)
x, y = meshgrid(xrange,yrange)
F1 = (((x/7) ** 2) * sqrt(abs(abs(x) - 3)/(abs(x) - 3)) + ((y / 3) ** 2) * sqrt(abs(y + (3 * sqrt(33)) / 7)/(y + (3 * sqrt(33)) / 7)) - 1)
F2 = (abs(x/2) - ((3 * sqrt(33) - 7)/112) * x**2 - 3 + sqrt(1 - (abs(abs(x) - 2) - 1) ** 2 ) - y)
F3 = (9 * sqrt(abs((abs(x) - 1) * (abs(x) - 3/4))/((1 - abs(x)) * (abs(x) - 3/4))) - 8 * abs(x) - y)
F4 = (3 * abs(x) + 0.75 * sqrt(abs((abs(x) - 3/4) * (abs(x) - 1/2))/((3/4 - abs(x)) * (abs(x) - 1/2))) - y)
F5 = ((9/4) * sqrt(abs((x - 1/2) * (x + 1/2))/((1/2 - x) * (1/2 + x))) - y)
F6 = ((6 * sqrt(10)) / 7 + (3/2 - abs(x)/2) * sqrt(abs(abs(x) - 1)/(abs(x) - 1)) - ((6 * sqrt(10))/ 14) * sqrt(4 - (abs(x) - 1) ** 2 ) - y)
for f in [F1,F2,F3,F4,F5,F6]:
matplotlib.pyplot.contour(x, y, f, [0])
matplotlib.pyplot.show()
the result plot:
I know this might seem lame, but how about creating a list of x values, and then computing the value of "batman" at each of those positions, and storing in another list. You could define a function "batman" which computes the y value for each x value you pass in.
Then just plot those lists with matplotlib.
EDIT: Since you've made numpy arrays already to store the results, you could use those when computing the y values.
I'm not even sure how this equation would work, since I see divisions by zero arising in the first term (under the first square root, when abs(x) = 3), and imaginary numbers showing up in the last term (under the last square root, when {abs(x)-1}^2 > 4, ie x > 3 or x < -3).
What am I missing here? Is only the real part of the result used, and are divisions by zero ignored or approximated?
Running this, I do indeed see lots of RunTimeWarnings, and it is not unlikely matplotlib would get totally confused what numbers to work with (NaNs, Infs; trying print F at the end). Looks like it still manages when there's only a relatively low number of NaNs or Infs, which would explain that you're seeing part of the figure.
I'd think matplotlib's contour is fine, just confused by the input.

Categories

Resources