How do I make an infinite series using an equation? - python

I'm trying to make a function called cos_series that uses values x and nterms that gives me the sum of a series, using this equation 1 - x^2/2! + x^4/4! - x^6/6! +...
This is my code so far,
def cos_series(x,nterms):
lst = []
lst2 = []
for i in range(nterms):
lst+=[x**(2*i)/(math.factorial(i*2))]
for i in range(nterms):
lst2+=[(x**(2*i)/(math.factorial(i*2)))*-1]
return sum(lst2[1::2] + lst[::2])
cos_series(math.pi/3,3)
The return value should equal 0.501796 but I'm having trouble reaching it, can anyone help?

Your code seems to work just fine.
Your logic works with just:
def cos_series(x, n):
return sum((-1 if (i % 2) else 1) * x**(i*2) / math.factorial(i*2) for i in range(n))
Generating the sum of the series in one go and avoiding the computation of values you don't use.
(note that, after you changed your question, your code in fact returns 0.501796201500181 - which is the value you expected; there's no issue?)

You don't need to use math.factorial() and you don't need to store the terms in a list. Just build the numerator and denominator as you go and add up them up.
By producing the numerator and denominator iteratively, your logic will be much easier to manage and debug:
def cos(x,nTerms=10):
result = 0
numerator = 1
denominator = 1
for even in range(2,nTerms*2+1,2): # nTerms even numbers
result += numerator / denominator # sum of terms
numerator *= -x*x # +/- for even powers of x
denominator *= even * (even-1) # factorial of even numbers
return result
print(cos(3.141592653589793/3,3)) # 0.501796201500181

Related

Subtraction in place of Division: How to approximate division with subtraction

I want to do division but with subtraction. I also don't necessarily want the exact answer.
No floating point numbers too (preferably)
How can this be achieved?
Thanks in advance:)
Also the process should almost be as fast as normal division.
to approximate x divided by y you can subtract y from x until the result is smaller or equal to 0 and then the result of the division would be the number of times you subtracted y from x. However this doesn't work with negatives numbers.
Well, let's say you have your numerator and your denominator. The division basically consists in estimating how many denominator you have in your numerator.
So a simple loop should do:
def divide_by_sub(numerator, denominator):
# Init
result = 0
remains = numerator
# Substract as much as possible
while remains >= denominator:
remains -= denominator
result += 1
# Here we have the "floor" part of the result
return result
This will give you the "floor" part of your result. Please consider adding some guardrails to handle "denominator is zero", "numerator is negative", etc.
My best guess, if you want go further, would be to then add an argument to the function for the precision you want like precision and then multiply remains by it (for instance 10 or 100), and reloop on it. It's doable recursively:
def divide_by_sub(numerator, denominator, precision):
# Init
result = 0
remains = numerator
# Substract as much as possible
while remains >= denominator:
remains -= denominator
result += 1
# Here we have the "floor" part of the result. We proceed to more digits
if precision > 1:
remains = remains * precision
float_result = divide_by_sub(remains, denominator, 1)
result += float_result/precision
return result
Giving you, for instance for divide_by_sub(7,3,1000) the following:
2.333

Stop Approximation in Complex Division in Python

I've been writing some code to list the Gaussian integer divisors of rational integers in Python. (Relating to Project Euler problem 153)
I seem to have reached some trouble with certain numbers and I believe it's to do with Python approximating the division of complex numbers.
Here is my code for the function:
def IsGaussian(z):
#returns True if the complex number is a Gaussian integer
return complex(int(z.real), int(z.imag)) == z
def Divisors(n):
divisors = []
#Firstly, append the rational integer divisors
for x in range(1, int(n / 2 + 1)):
if n % x == 0:
divisors.append(x)
#Secondly, two for loops are used to append the complex Guassian integer divisors
for x in range(1, int(n / 2 + 1)):
for y in range(1, int(n / 2 + 1)):
if IsGaussian(n / complex(x, y)) == n:
divisors.append(complex(x, y))
divisors.append(complex(x, -y))
divisors.append(n)
return divisors
When I run Divisors(29) I get [1, 29], but this is missing out four other divisors, one of which being (5 + 2j), which can clearly be seen to divide into 29.
On running 29 / complex(5, 2), Python gives (5 - 2.0000000000000004j)
This result is incorrect, as it should be (5 - 2j). Is there any way to somehow bypass Python's approximation? And why is it that this problem has not risen for many other rational integers under 100?
Thanks in advance for your help.
Internally, CPython uses a pair of double-precision floats for complex numbers. The behavior of numerical solutions in general is too complicated to summarize here, but some error is unavoidable in numerical calculations.
EG:
>>>print(.3/3)
0.09999999999999999
As such, it is often correct to use approximate equality rather than actual equality when testing solutions of this kind.
The isclose function in the cmath module is available for this exact reason.
>>>print(.3/3 == .1)
False
>>>print(isclose(.3/3, .1))
True
This kind of question is the domain of Numerical Analysis; this may be a useful tag for further questions on this subject.
Note that it is considered 'pythonic' for function identifiers to be in snake_case.
from cmath import isclose
def is_gaussian(z):
#returns True if the complex number is a Gaussian integer
rounded = complex(round(z.real), round(z.imag))
return isclose(rounded, z)
You could define an epsilon, by using round to round to the desired number of decimal places/precision (e.g. 10):
def IsGaussian(z, prec=10):
# returns True if the complex number is a Gaussian integer
# rounds the input number to the `prec` number of digits
z = complex(round(z.real,prec), round(z.imag,prec))
return complex(int(z.real), int(z.imag)) == z
Your code has another issue though:
if IsGaussian(n / complex(x, y)) == n:
This will only give results for n = 0 or n = 1. You probably want to remove the check for equality.

Programming a math function in python

This is what I have to program:
sen(x) = (x/1!) - (x^3/3!) + (x^5/5!) - (x^7/7!) + ...
So far I have this:
def seno(x, n):
for i in range(1, n+1, 2):
result = (x**i/math.factorial(i))
result1 = (x**i/math.factorial(i))
result2 = (x**i/math.factorial(i))
result3 = (x**i/math.factorial(i))
return math.sin(result-result1 + result2 - result3)
The thing I can’t understand is how to actually change the i value for each result.
Another thing is I can’t use any non-built-in function. So no imports except for the math.
EDIT: Thank you for the quick reply.
It looks like you're doing a Taylor Series approximation of Sine.
You probably shouldn't declare separate result1, result2, etc. Instead, you compute each value in a loop, and accumulate it in a single result variable.
def seno(x,n):
result = 0
sign = 1 # Sign starts out positive
for i in range(1, n+1, 2):
result += x**i/math.factorial(i)
sign *= -1 # use negative sign on odd terms
return result
Note that you don't actually call math.sin on the result. The whole point of using a Taylor Series approximation is to estimate the value of math.sin(x) without actually calling that function.
You can optimize this loop a bit more. You can do a strength reduction on math.factorial by accumulating the answer rather than recomputing the whole factorial value on each iteration. You can also do a similar strength reduction on the x**i term, and roll the sign-switching logic into the update logic for exp as well.
def seno(x,n):
result = 0.0
fact = 1.0 # start with '1!'
exp = x # start with 'x¹'
xx = x*x # xx = x²
for i in range(1, n+1, 2):
result += exp / fact
exp *= -xx # update exponential term to 'xⁱ', and swap sign
fact *= (i+1) * (i+2) # update factorial term to '(i+2)!'
return result
You are using the for loop incorrectly. Each iteration will compute one term of the series; you need to accumulate those values rather than trying to set 4 results at a time.
def seno(x, n):
sign = 1
result = 0
for i in range(1, n+1, 2):
term = x**i/math.factorial(i)
result += sign * term
sign *= -1 # Alternate the sign of the term
return result

Trapezoid Rule in Python

I am trying to write a program using Python v. 2.7.5 that will compute the area under the curve y=sin(x) between x = 0 and x = pi. Perform this calculation varying the n divisions of the range of x between 1 and 10 inclusive and print the approximate value, the true value, and the percent error (in other words, increase the accuracy by increasing the number of trapezoids). Print all the values to three decimal places.
I am not sure what the code should look like. I was told that I should only have about 12 lines of code for these calculations to be done.
I am using Wing IDE.
This is what I have so far
# base_n = (b-a)/n
# h1 = a + ((n-1)/n)(b-a)
# h2 = a + (n/n)(b-a)
# Trap Area = (1/2)*base*(h1+h2)
# a = 0, b = pi
from math import pi, sin
def TrapArea(n):
for i in range(1, n):
deltax = (pi-0)/n
sum += (1.0/2.0)(((pi-0)/n)(sin((i-1)/n(pi-0))) + sin((i/n)(pi-0)))*deltax
return sum
for i in range(1, 11):
print TrapArea(i)
I am not sure if I am on the right track. I am getting an error that says "local variable 'sum' referenced before assignment. Any suggestions on how to improve my code?
Your original problem and problem with Shashank Gupta's answer was /n does integer division. You need to convert n to float first:
from math import pi, sin
def TrapArea(n):
sum = 0
for i in range(1, n):
deltax = (pi-0)/n
sum += (1.0/2.0)*(((pi-0)/float(n))*(sin((i-1)/float(n)*(pi-0))) + sin((i/float(n))*(pi-0)))*deltax
return sum
for i in range(1, 11):
print TrapArea(i)
Output:
0
0.785398163397
1.38175124526
1.47457409274
1.45836902046
1.42009115659
1.38070223089
1.34524797198
1.31450259385
1.28808354
Note that you can heavily simplify the sum += ... part.
First change all (pi-0) to pi:
sum += (1.0/2.0)*((pi/float(n))*(sin((i-1)/float(n)*pi)) + sin((i/float(n))*pi))*deltax
Then do pi/n wherever possible, which avoids needing to call float as pi is already a float:
sum += (1.0/2.0)*(pi/n * (sin((i-1) * pi/n)) + sin(i * pi/n))*deltax
Then change the (1.0/2.0) to 0.5 and remove some brackets:
sum += 0.5 * (pi/n * sin((i-1) * pi/n) + sin(i * pi/n)) * deltax
Much nicer, eh?
You have some indentation issues with your code but that could just be because of copy paste. Anyways adding a line sum = 0 at the beginning of your TrapArea function should solve your current error. But as #Blender pointed out in the comments, you have another issue, which is the lack of a multiplication operator (*) after your floating point division expression (1.0/2.0).
Remember that in Python expressions are not always evaluated as you would expect mathematically. Thus (a op b)(c) will not automatically multiply the result of a op b by c like you would expect with a mathematical expression. Instead this is the function call notation in Python.
Also remember that you must initialize all variables before using their values for assignment. Python has no default value for unnamed variables so when you reference the value of sum with sum += expr which is equivalent to sum = sum + expr you are trying to reference a name (sum) that is not binded to any object at all.
The following revision to your function should do the trick. Notice how I place multiplication operators (*) between every expression that you intend to multiply.
def TrapArea(n):
sum = 0
for i in range(1, n):
i = float(i)
deltax = (pi-0)/n
sum += (1.0/2.0)*(((pi-0)/n)*(sin((i-1)/n*(pi-0))) + sin((i/n)*(pi-0)))*deltax
return sum
EDIT: I also dealt with the float division issue by converting i to float(i) within every iteration of the loop. In Python 2.x, if you divide one integer type object with another integer type object, the expression evaluates to an integer regardless of the actual value.
A "nicer" way to do the trapezoid rule with equally-spaced points...
Let dx = pi/n be the width of the interval. Also, let f(i) be sin(i*dx) to shorten some expressions below. Then interval i (in range(1,n)) contributes:
dA = 0.5*dx*( f(i) + f(i-1) )
...to the sum (which is an area, so I'm using dA for "delta area"). Factoring out the 0.5*dx, makes the whole some look like:
A = 0.5*dx * ( (f(0) + f(1)) + (f(1) + f(2)) + .... + (f(n-1) + f(n)) )
Notice that there are two f(1) terms, two f(2) terms, on up to two f(n-1) terms. Combine those to get:
A = 0.5*dx * ( f(0) + 2*f(1) + 2*f(2) + ... + 2*f(n-1) + f(n) )
The 0.5 and 2 factors cancel except in the first and last terms:
A = 0.5*dx(f(0) + f(n)) + dx*(f(1) + f(2) + ... + f(n-1))
Finally, you can factor dx out entirely to do just one multiplication at the end. Converting back to sin() calls, then:
def TrapArea(n):
dx = pi/n
asum = 0.5*(sin(0) + sin(pi)) # this is 0 for this problem, but not others
for i in range(1, n-1):
asum += sin(i*dx)
return sum*dx
That changed "sum" to "asum", or maybe "area" would be better. That's mostly because sum() is a built-in function, which I'll use below the line.
Extra credit: The loop part of the sum can be done in one step with a generator expression and the sum builtin function:
def TrapArea2(n):
dx = pi/n
asum = 0.5*(sin(0) + sin(pi))
asum += sum(sin(i*dx) for i in range(1,n-1))
return asum*dx
Testing both of those:
>>> for n in [1, 10, 100, 1000, 10000]:
print n, TrapArea(n), TrapArea2(n)
1 1.92367069372e-16 1.92367069372e-16
10 1.88644298557 1.88644298557
100 1.99884870579 1.99884870579
1000 1.99998848548 1.99998848548
10000 1.99999988485 1.99999988485
That first line is a "numerical zero", since math.sin(math.pi) evaluates to about 1.2e-16 instead of exactly zero. Draw the single interval from 0 to pi and the endpoints are indeed both 0 (or nearly so.)

floating points precision in complicated calculations

For calculating Catalan Numbers, I wrote two codes. One (def "Catalan") works recursively and returns the right Catalan Numbers.
dicatalan = {}
def catalan(n):
if n == 0:
return 1
else:
res = 0
if n not in dicatalan:
for i in range(n):
res += catalan(i) * catalan(n - i - 1)
dicatalan[n] = res
return dicatalan[n]
the other (def "catalanFormula") applies the implicit formula, but doesn't calculate accurately starting from n=30. the problem derives from floating points - for k=9 the program returns "6835971.999999999" instead of "6835972" and from this moment on accumulates mistakes till the final wrong answer.
(print line is for checking)
def catalanFormula(n):
result = 1
for k in range(2, n + 1):
result *= ((n + k) / k)
print (result)
return int(result)
I tried rounding and failed, tried Decimal import and still got nothing right.
I need the "catalanFormula" work perfectly as "catalan";
Any Ideas?
Thanks!
Try calculating the numerator and denominator separately and dividing them at the end. If you do this, you should be able to make it a little bit farther with floating-point.
I'm sure Python has a package for rational numbers. Using rationals is an even better idea.
See the bigfloat package.
from bigfloat import *
setcontext(quadruple_precision)
def catalanFormula(n):
result = BigFloat(1)
for k in range(2, n + 1):
result *= ((BigFloat(n) + BigFloat(k)) / BigFloat(k))
return result
catalanFormula(30)
Output:
BigFloat.exact('3814986502092304.00000000000000000043', precision=113)

Categories

Resources