Since factoring a quadratic equation in my head just happens, and has done that since I learned it - how would I go about starting to write a quadratic factorer in Python?
Improving Keiths's answer:
Start with a polynomial P(x) = a*x^2 + b*x + c.
Use the quadratic formula (or another method of your choice) to find the roots r1 and r2 to P(x) = 0.
You can now factor P(x) as a*(x-r1)(x-r2).
If your factor (3x - 4)(x - 9) the solution will be 3*(x - 4/3)(x - 9).
You might want to find a way to multiply the 3 into the factors to get rid of fractions / look pretty. In this case, it might help to use fraction arithmetic instead of doubles so you can know the denominators better.
Use the quadratic formula.
I tried implementing hugomg's approach. I stole the "gcd" and "simplify fraction" function from online. Here is my sloppy approach:
from math import sqrt
def gcd(a, b):
while b:
a, b = b, a % b
return a
def simplify_fraction(numer, denom):
if denom == 0:
return "Division by 0 - result undefined"
# Remove greatest common divisor:
common_divisor = gcd(numer, denom)
(reduced_num, reduced_den) = (numer / common_divisor, denom / common_divisor)
# Note that reduced_den > 0 as documented in the gcd function.
if common_divisor == 1:
return (numer, denom)
else:
# Bunch of nonsense to make sure denominator is negative if possible
if (reduced_den > denom):
if (reduced_den * reduced_num < 0):
return(-reduced_num, -reduced_den)
else:
return (reduced_num, reduced_den)
else:
return (reduced_num, reduced_den)
def quadratic_function(a,b,c):
if (b**2-4*a*c >= 0):
x1 = (-b+sqrt(b**2-4*a*c))/(2*a)
x2 = (-b-sqrt(b**2-4*a*c))/(2*a)
# Added a "-" to these next 2 values because they would be moved to the other side of the equation
mult1 = -x1 * a
mult2 = -x2 * a
(num1,den1) = simplify_fraction(a,mult1)
(num2,den2) = simplify_fraction(a,mult2)
if ((num1 > a) or (num2 > a)):
# simplify fraction will make too large of num and denom to try to make a sqrt work
print("No factorization")
else:
# Getting ready to make the print look nice
if (den1 > 0):
sign1 = "+"
else:
sign1 = ""
if (den2 > 0):
sign2 = "+"
else:
sign2 = ""
print("({}x{}{})({}x{}{})".format(int(num1),sign1,int(den1),int(num2),sign2,int(den2)))
else:
# if the part under the sqrt is negative, you have a solution with i
print("Solutions are imaginary")
return
# This function takes in a, b, and c from the equation:
# ax^2 + bx + c
# and prints out the factorization if there is one
quadratic_function(7,27,-4)
If I run this I get the output:
(7x-1)(1x+4)
Related
I want to write a function of cos(x) using the Taylor Expansion, but not using the math.factorial function.
I defined the factorial of 2i as:
def factorial_two(i):
if i < 0:
#Handling negative numbers
print("Error: can't compute the factorial of a negative number!")
return None
elif i == 0:
#The special case i = 0
return 1
else:
i = i * 2
#The general case
fact = 1
while i > 0:
fact = fact * i
i = i - 1
return fact
Then I defined the approximation of cosine as:
def cosine_approx(x,n):
sum = 0
for i in range(0, n+1):
sum += ((-1) ** i) * (x**(2*i)/ factorial_two(i))
return sum
When I run this for any x and any n I always get 1.0 as the result. When I tried the exact same function for cosine_approx(x,n), but instead use the basic math.factorial(2*i) I get the correct results. So the question is, where did I go wrong with by definition? Or am I not using it correctly?
Thank you in advance.
your code has an error you put return sum in the for loop!!
so sum always be 1.0 and returend.
you should put that out of for loop.
for i in range(0, n+1):
sum += ((-1) ** i) * (x**(2*i)/ factorial_two(i))
return sum
like that.
I´m solving a problem in which i have to print all the fibonacci numbers such that:
a <= f <= b
And i would like to start them by the smallest fibonacci number that is greater than or equal to a, in order to make my program run faster. For that, i need to define a variable "n", such that the nth Fibonacci number satisfies the condition above (smallest one that is greater than or equal to a). To define such variable, i need to find the smallest "n" that satisfies the fibonacci(n) general term equation.
I tried to find it by making a for loop, but it just ends up being as slow as if i started to check from the first Fibonacci Number. Anyone has any ideas on how to define it efficiently?
P.S. Here is my attempted code:
from math import sqrt, log, ceil
def Fibo(n):
if n == 1: return 1
elif n == 2: return 2
return Fibo(n-1) + Fibo(n-2)
while True:
try:
a, b = [int(i) for i in input().split()]
cont = 0
phi = (sqrt(5) + 1) / 2
i = ceil(log(a * sqrt(5), phi))
if Fibo(i-1) >= a: i -= 1
elif Fibo(n) < a: i += 1
while True:
if a <= Fibo(i) <= b: cont += 1
elif Fibo(i) > b:
break
i -= 1
print(cont)
except input() == "0 0":
break
Probably the most useful formula for your purpose for F(n), the nth Fibonacci number, is
from math import sqrt
phi = (sqrt(5) + 1) / 2 # the golden ratio
F(n) = round(phi**n / sqrt(5))
Therefore, one formula to get the value of n for a given value of a is
from math import sqrt, log, ceil
phi = (sqrt(5) + 1) / 2 # the golden ratio
n = ceil(log(a * sqrt(5), phi))
Due to approximation and rounding issues, you should check the values of n-1, n, and n+1 to ensure you got exactly the desired value. If you do this often, you should pre-define variables holding the value of the golden ratio and of the square root of five. If your value of a is too large for the float type to store it accurately, you would need a more complicated routine to handle the larger number.
For an assignment, I must create a program with a function that replaces the "power function" assuming that it is broken for whatever reason. The current model I have works pretty decently, but I'm struggling to get it to work when raising to a 1/2, 1/4, etc. (essentially performing a square root function). I know that the issue lies within floats not cooperating with range, but I personally don't know how to avoid this
def power (value, exp):
num = 1.0
if exp>0:
for function in range(exp):
num = num * value
elif exp<0:
for function in range(-exp):
num = num / value
else:
num = 1
return num
number = float(raw_input("Please enter a the base number you wish to raise to a power (no fractions, decimal allowed): "))
exponent = float(raw_input("Please enter the power you wish to raise the base number to (no fractions, decimal allowed): "))
print "Your base number was:", number
print "You rasied this number to the power of:", exponent
print "The ending product of this operation is:", power(number, exponent)
Fractional powers are a bit tricky, but you can use the fact that bn/d = (bn)1/d = d√ bn. See here for details. So you could write a recursive algorithm that
reduces the exponent until it is a float between 0 and 1
approximates a fraction n/d representing that float, e.g. using fractions or this
find the dth root of the n power, e.g. using simple binary search
Code:
def power(b, e):
# the simple cases
if e == 0: return 1
if b in (0, 1): return b
if e < 0: return 1 / power(b, -e)
if e >= 1: return b * power(b, e - 1)
# fractions: b^(n/d) == d-/ b^n
n, d = float_to_fraction(e) # see linked answer
return root(power(b, n), d)
def root(x, r):
if x < 0: raise ValueError("No roots of negative numbers!")
low, high = 0, x
cur = (low + high) / 2
while high - low > 0.001:
if power(cur, r) < x:
low = cur
else:
high = cur
cur = (low + high) / 2
return cur
Example:
>>> b, e = 1.23, -4.56
>>> b**e
0.38907443175580797
>>> power(b, e))
0.38902984218983117
Or you could just use logarithms, although that might be considered cheating:
>>> math.exp(e * math.log(b))
0.38907443175580797
I'm trying to write a program that takes an angle in degrees, and approximates the sin and cos value based on a number of given terms that the user chooses. In case you don't know
how to find sin and cos. So, with that being said, here is my current code:
import math
def main():
print()
print("Program to approximate sin and cos.")
print("You will be asked to enter an angle and \na number of terms.")
print("Written by ME")
print()
sinx = 0
cosx = 0
x = int(input("Enter an angle (in degrees): "))
terms = int(input("Enter the number of terms to use: "))
print()
for i in range(1, terms+1):
sinx = sinx + getSin(i, x)
cosx = cosx + getCos(i, x)
print(cosx, sinx)
def getSin(i, x):
if i == 1:
return x
else:
num, denom = calcSinFact(i, x)
sin = num/denom
return sin
def getCos(i, x):
if i == 1:
return 1
else:
num, denom = calcCosFact(i, x)
cos = num/denom
return cos
def calcSinFact(i, x):
if i % 2 == 1:
sign = -1
if i % 2 == 0:
sign = +1
denom = math.factorial(i*2-1)
num = sign * (x**(i*2-1))
return num, denom
def calcCosFact(i, x):
if i % 2 == 1:
sign = -1
if i % 2 == 0:
sign = +1
denom = math.factorial(i*2)
num = sign * (x**(i*2))
return num, denom
It runs but if i use the example shown in the picture above, i get cos = -162527117141.85715 and sin = -881660636823.117. So clearly something is off. In the picture above the answers should be cos = 0.50000000433433 and sin = 0.866025445100. I'm assuming it's the way I'm adding together the values in the first loop but i could be wrong. Any help is appreciated!
There are several issues here as pointed out in Russell Borogove's comments.
Issue no 1 is that the formulas you are using
(see wikipedia) expect x to be in radians not degrees. Going once round a circle is 360 degrees or 2*pi, so you can convert from degrees to radians by multipling by pi/180, as shown below in python code to incorrectly and then correctly get the sin of 90 degrees.
>>> math.sin(90)
0.8939966636005579
>>> math.sin(90*math.pi/180)
1.0
Issue no 2 is the rest of the code. As pointed out in the comments, there are some bugs, and the best way to find them would be to use some strategic print statements. However, you could write your program with far fewer lines of code, and simpler programs tend to have fewer bugs and be easier to debug if they do have problems.
As this is an assignment, I won't do it for you, but a related example is the series for sinh(x).
(again from wikipedia)
You can produce the terms in "one shot", using a Python list comprehension. The list can be printed and summed to get the result, as in the program below
x = 90 * math.pi / 180 # 90 degrees
n = 5
terms = [x**(2*i+1)/math.factorial(2*i+1) for i in range(n)]
print terms
sinh = sum(terms)
print sinh, math.sinh(x)
The output of this program is
[1.5707963267948966, 0.6459640975062462, 0.07969262624616703, 0.004681754135318687, 0.00016044118478735975]
2.30129524587 2.30129890231
I produced the Python list comprehension code directly from the mathematical formula for the summation, which is conveniently given in "Sigma" notation on the left hand side. You can produce sin and cos in a similar way. The one missing ingredient you need is the signs at each point in the series. The mathematical formulas tell you you need (-1)n. The Python equivalent is (-1)**n, which can be slotted into the appropriate place in the list comprehension code.
First, a few notes. It's better to print \n at the end of the previous print or at the beginning of the following then empty print().
It's useful to use a debugging tool, use logging module or just use print and find the bug by comparing expected values with returned values.
Here is a code that is working for me:
import math
def main():
print()
print("Program to approximate sin and cos.")
print("You will be asked to enter an angle and \na number of terms.")
print("Written by ME")
print()
sinx = 0
cosx = 0
x = int(input("Enter an angle (in degrees): "))
terms = int(input("Enter the number of terms to use: "))
print()
x = x / 180.0 * math.pi; # added
for i in range(1, terms+1):
sinx = sinx + getSin(i, x)
cosx = cosx + getCos(i, x)
print("Cos:{0}, Sinus:{1}".format(cosx,sinx)); # changed
def getSin(i, x):
if i == 1:
return x
else:
num, denom = calcSinFact(i, x)
sin = float(num)/denom # changed
return sin
def getCos(i, x):
if i == 1:
return 1
else:
num, denom = calcCosFact(i, x)
cos = float(num)/denom # changed
return cos
def calcSinFact(i, x):
if i % 2 == 1:
sign = +1 # changed
if i % 2 == 0:
sign = -1 # changed
denom = math.factorial(i*2-1)
num = sign * (x**(i*2-1))
return num, denom
def calcCosFact(i, x):
if i % 2 == 1:
sign = +1 # changed
if i % 2 == 0:
sign = -1 # changed
denom = math.factorial(i*2-2) # changed
num = sign * (x**(i*2-2)) # changed
return num, denom
And what I have changed? (I hope I won't forget anything)
Your sign variables were wrong. Just the opposite. So I changed the signes in the conditions.
It is perhaps not necessary but I added conversion from int to float when you divided num by denom.
According to the definition of the approximation, the input x is in radians. So I added conversion from degrees to radians. x = x / 180.0 * math.pi;
Your index in calcCosFact was wrong. It was always higher by 2. (i.e. 4 instead of 2, 8 instead of 6...)
I got this result:
Enter an angle (in degrees): 180 Enter the number of terms to use: 5
Cos:-0.976022212624, Sinus:0.00692527070751
It should be correct now. I can also recommend WolphramAlpha when you need to quickly do some math.
Here is an improved version:
from math import radians
import sys
# version compatibility shim
if sys.hexversion < 0x3000000:
# Python 2.x
inp = raw_input
rng = xrange
else:
# Python 3.x
inp = input
rng = range
def type_getter(type):
def fn(prompt):
while True:
try:
return type(inp(prompt))
except ValueError:
pass
return fn
get_float = type_getter(float)
get_int = type_getter(int)
def calc_sin(theta, terms):
# term 0
num = theta
denom = 1
approx = num / denom
# following terms
for n in rng(1, terms):
num *= -theta * theta
denom *= (2*n) * (2*n + 1)
# running sum
approx += num / denom
return approx
def calc_cos(theta, terms):
# term 0
num = 1.
denom = 1
approx = num / denom
# following terms
for n in rng(1, terms):
num *= -theta * theta
denom *= (2*n - 1) * (2*n)
# running sum
approx += num / denom
return approx
def main():
print(
"\nProgram to approximate sin and cos."
"\nYou will be asked to enter an angle and"
"\na number of terms."
)
theta = get_float("Enter an angle (in degrees): ")
terms = get_int ("Number of terms to use: ")
print("sin({}) = {}".format(theta, calc_sin(radians(theta), terms)))
print("cos({}) = {}".format(theta, calc_cos(radians(theta), terms)))
if __name__=="__main__":
main()
Note that because the Maclaurin series is centered on x=0, values of theta closer to 0 will converge much faster: calc_sin(radians(-90), 5) is -1.00000354258 but calc_sin(radians(270), 5) is -0.444365928238 (about 157,000 times further from the correct value of -1.0).
One can completely avoid all power and factorial computations by using and combining the recursive definitions of factorial and integer powers. Further optimization is obtained by computing both cos and sin values at once, so that the powers are only computed once.
PI = 3.1415926535897932384;
RadInDeg=PI/180;
def getCosSin(x, n):
mxx = -x*x;
term = 1;
k = 2;
cossum = 1;
sinsum = 1;
for i in range(n):
term *= mxx
term /= k; k+=1
cossum += term
term /= k; k+=1
sinsum += term
return cossum, x*sinsum
def main():
print "\nProgram to approximate sin and cos."
print "You will be asked to enter an angle and \na number of terms."
x = int(input("Enter an angle (in degrees): "))
terms = int(input("Enter the number of terms to use: "))
print
x = x*RadInDeg;
cosx, sinx = getCosSin(x,terms)
print cosx, sinx
if __name__=="__main__":
main()
For a numerical methods class, I need to write a program to evaluate a definite integral with Simpson's composite rule. I already got this far (see below), but my answer is not correct. I am testing the program with f(x)=x, integrated over 0 to 1, for which the outcome should be 0.5. I get 0.78746... etc.
I know there is a Simpson's rule available in Scipy, but I really need to write it myself.
I suspect there is something wrong with the two loops. I tried "for i in range(1, n, 2)" and "for i in range(2, n-1, 2)" before, and this gave me a result of 0.41668333... etc.
I also tried "x += h" and I tried "x += i*h". The first gave me 0.3954, and the second option 7.9218.
# Write a program to evaluate a definite integral using Simpson's rule with
# n subdivisions
from math import *
from pylab import *
def simpson(f, a, b, n):
h=(b-a)/n
k=0.0
x=a
for i in range(1,n/2):
x += 2*h
k += 4*f(x)
for i in range(2,(n/2)-1):
x += 2*h
k += 2*f(x)
return (h/3)*(f(a)+f(b)+k)
def function(x): return x
print simpson(function, 0.0, 1.0, 100)
You probably forget to initialize x before the second loop, also, starting conditions and number of iterations are off. Here is the correct way:
def simpson(f, a, b, n):
h=(b-a)/n
k=0.0
x=a + h
for i in range(1,n/2 + 1):
k += 4*f(x)
x += 2*h
x = a + 2*h
for i in range(1,n/2):
k += 2*f(x)
x += 2*h
return (h/3)*(f(a)+f(b)+k)
Your mistakes are connected with the notion of a loop invariant. Not to get into details too much, it's generally easier to understand and debug cycles which advance at the end of a cycle, not at the beginning, here I moved the x += 2 * h line to the end, which made it easy to verify where the summation starts. In your implementation it would be necessary to assign a weird x = a - h for the first loop only to add 2 * h to it as the first line in the loop.
All you need to do to make this code work is add a variable for a and b in the function bounds() and add a function in f(x) that uses the variable x. You could also implement the function and bounds directly into the simpsonsRule function if desired... Also, these are functions to be implimented into a program, not a program itself.
def simpsonsRule(n):
"""
simpsonsRule: (int) -> float
Parameters:
n: integer representing the number of segments being used to
approximate the integral
Pre conditions:
Function bounds() declared that returns lower and upper bounds of integral.
Function f(x) declared that returns the evaluated equation at point x.
Parameters passed.
Post conditions:
Returns float equal to the approximate integral of f(x) from a to b
using Simpson's rule.
Description:
Returns the approximation of an integral. Works as of python 3.3.2
REQUIRES NO MODULES to be imported, especially not non standard ones.
-Code by TechnicalFox
"""
a,b = bounds()
sum = float()
sum += f(a) #evaluating first point
sum += f(b) #evaluating last point
width=(b-a)/(2*n) #width of segments
oddSum = float()
evenSum = float()
for i in range(1,n): #evaluating all odd values of n (not first and last)
oddSum += f(2*width*i+a)
sum += oddSum * 2
for i in range(1,n+1): #evaluating all even values of n (not first and last)
evenSum += f(width*(-1+2*i)+a)
sum += evenSum * 4
return sum * width/3
def bounds():
"""
Description:
Function that returns both the upper and lower bounds of an integral.
"""
a = #>>>INTEGER REPRESENTING LOWER BOUND OF INTEGRAL<<<
b = #>>>INTEGER REPRESENTING UPPER BOUND OF INTEGRAL<<<
return a,b
def f(x):
"""
Description:
Function that takes an x value and returns the equation being evaluated,
with said x value.
"""
return #>>>EQUATION USING VARIABLE X<<<
You can use this program for calculating definite integrals by using Simpson's 1/3 rule. You can increase your accuracy by increasing the value of the variable panels.
import numpy as np
def integration(integrand,lower,upper,*args):
panels = 100000
limits = [lower, upper]
h = ( limits[1] - limits[0] ) / (2 * panels)
n = (2 * panels) + 1
x = np.linspace(limits[0],limits[1],n)
y = integrand(x,*args)
#Simpson 1/3
I = 0
start = -2
for looper in range(0,panels):
start += 2
counter = 0
for looper in range(start, start+3):
counter += 1
if (counter ==1 or counter == 3):
I += ((h/3) * y[looper])
else:
I += ((h/3) * 4 * y[looper])
return I
For example:
def f(x,a,b):
return a * np.log(x/b)
I = integration(f,3,4,2,5)
print(I)
will integrate 2ln(x/5) within the interval 3 and 4
There is my code (i think that is the most easy method). I done this in jupyter notebook.
The easiest and most accurate code for Simpson method is 1/3.
Explanation
For standard method (a=0, h=4, b=12) and f=100-(x^2)/2
We got:
n= 3.0, y0 = 100.0, y1 = 92.0, y2 = 68.0, y3 = 28.0,
So simpson method = h/3*(y0+4*y1+2*y2+y3) = 842,7 (this is not true).
Using 1/3 rule we got:
h = h/2= 4/2= 2 and then:
n= 3.0, y0 = 100.0, y1 = 98.0, y2 = 92.0, y3 = 82.0, y4 = 68.0, y5 = 50.0, y6 = 28.0,
Now we calculate the integral for each step (n=3 = 3 steps):
Integral of the first step: h/3*(y0+4*y1+y2) = 389.3333333333333
Integral of the second step: h/3*(y2+4*y3+y4) = 325.3333333333333
Integral of the third step: h/3*(y4+4*y5+y6) = 197.33333333333331
Sum all, and we get 912.0 AND THIS IS TRUE
x=0
b=12
h=4
x=float(x)
h=float(h)
b=float(b)
a=float(x)
def fun(x):
return 100-(x**2)/2
h=h/2
l=0 #just numeration
print('n=',(b-x)/(h*2))
n=int((b-a)/h+1)
y = [] #tablica/lista wszystkich y / list of all "y"
yf = []
for i in range(n):
f=fun(x)
print('y%s' %(l),'=',f)
y.append(f)
l+=1
x+=h
print(y,'\n')
n1=int(((b-a)/h)/2)
l=1
for i in range(n1):
nf=(h/3*(y[+0]+4*y[+1]+y[+2]))
y=y[2:] # with every step, we deleting 2 first "y" and we move 2 spaces to the right, i.e. y2+4*y3+y4
print('Całka dla kroku/Integral for a step',l,'=',nf)
yf.append(nf)
l+=1
print('\nWynik całki/Result of the integral =', sum(yf) )
At the beginning I added simple data entry:
d=None
while(True):
print("Enter your own data or enter the word "test" for ready data.\n")
x=input ('Enter the beginning of the interval (a): ')
if x == 'test':
x=0
h=4 #krok (Δx)
b=12 #granica np. 0>12
#w=(20*x)-(x**2) lub (1+x**3)**(1/2)
break
h=input ('Enter the size of the integration step (h): ')
if h == 'test':
x=0
h=4
b=12
break
b=input ('Enter the end of the range (b): ')
if b == 'test':
x=0
h=4
b=12
break
d=input ('Give the function pattern: ')
if d == 'test':
x=0
h=4
b=12
break
elif d != -9999.9:
break
x=float(x)
h=float(h)
b=float(b)
a=float(x)
if d == None or d == 'test':
def fun(x):
return 100-(x**2)/2 #(20*x)-(x**2)
else:
def fun(x):
w = eval(d)
return w
h=h/2
l=0 #just numeration
print('n=',(b-x)/(h*2))
n=int((b-a)/h+1)
y = [] #tablica/lista wszystkich y / list of all "y"
yf = []
for i in range(n):
f=fun(x)
print('y%s' %(l),'=',f)
y.append(f)
l+=1
x+=h
print(y,'\n')
n1=int(((b-a)/h)/2)
l=1
for i in range(n1):
nf=(h/3*(y[+0]+4*y[+1]+y[+2]))
y=y[2:]
print('Całka dla kroku/Integral for a step',l,'=',nf)
yf.append(nf)
l+=1
print('\nWynik całki/Result of the integral =', sum(yf) )
def simps(f, a, b, N): # N must be an odd integer
""" define simpson method, a and b are the lower and upper limits of
the interval, N is number of points, dx is the slice
"""
integ = 0
dx = float((b - a) / N)
for i in range(1,N-1,2):
integ += f((a+(i-1)*dx)) + 4*f((a+i*dx)) + f((a+(i+1)*dx))
integral = dx/3.0 * integ
# if number of points is even, then error araise
if (N % 2) == 0:
raise ValueError("N must be an odd integer.")
return integral
def f(x):
return x**2
integrate = simps(f,0,1,99)
print(integrate)
Example of implementing Simpson's rule for integral sinX with a = 0 and b = pi/4. And use 10 panels for the integration
def simpson(f, a, b, n):
x = np.linspace(a, b, n+1)
w = 2*np.ones(n+1); w[0] = 1.0; w[-1] = 1;
for i in range(len(w)):
if i % 2 == 1:
w[i] = 4
width = x[1] - x[0]
area = 0.333 * width * np.sum( w*f(x))
return area
f = lambda x: np.sin(x)
a = 0.0; b = np.pi/4
areaSim = simpson(f, a, b, 10)
print(areaSim)