I need to solve a non-linear function.
Problem: logical errors in the structure of the code with the refinement of the root by the method of half division. Please help me figure it out and point out errors (def utoch()).
Code structure:
I tabulate the function and write the argument and function value
from this argument into a two-dimensional array AB 10 by 2 .
Next, I separate the roots (find a small [a; b] in which there is
one root: a and b must be of different signs). I enter in the array
AB 3 by 5, such a and b in 1 and 2 columns.
Now I need to use the method of refining the roots by the method of
half division. The AB array is entered in column 3 - the root, in 4
-the value of the function from the root, 5 - the number of steps to find this root
I also attach block diagrams, but they are created for BASIC
import math
xn = 1
xk = 3
dx = 0.2
N = 10
XY = [[0.0] * 2 for b in range(10+1)]
AB = [[0.0] * 5 for q in range(3)]
def f(x):
return (math.atan(x) + math.sin(x)-2)
def TabXY():
for i in range(N+1):
x = xn + dx*i
XY[i][0] = float(round(x,1))
XY[i][1] = float(round(f(x),3))
return(XY)
print(TabXY())
def otd():
Nr = 0
for i in range(1, N+1):
if XY[i-1][1] * XY[i][1] < 0 :
AB[Nr][0] = XY[i-1][1]
AB[Nr][1] = XY[i][1]
Nr = Nr + 1
return(AB)
print(otd())
def utoch():
Nk= 3
for i in range(0,Nk):
a = AB[i][0]
b = AB[i][1]
Fa = f(a)
while abs(b-a) < 0.001:
c = float((a + b) / 2)
Fc = f(c)
if Fa * Fc < 0:
a = c
Fa = Fc
else:
b = c
AB[i][2] = c
AB[i][3] = Fc
return (AB)
print(utoch())
to utoch
Related
I am trying to code the Chudnovsky algorithm in python. However, when I run my code, it gives me a very small number (-5.051212624421025e-55) which is not pi. I am in middle school, and I don't know anybody that can help me. What am I doing wrong?
Here is a link to the Chudnovsky formula: https://levelup.gitconnected.com/generating-the-value-of-pi-to-a-known-number-of-decimals-places-in-python-e93986bb474d
Here is my code:
import math
def fact(exi):
memory = exi
for i in range(1, exi):
memory *= i
return memory
k = 10
s = 0
for i in range(0, k):
a = -1^k
b = fact(6*k)
c = (545140134*k) + 13591409
d = fact(3*k)
e = (fact(k))^3
f = (3 * k) + 3/2
g = math.pow(640320, f)
numerator = (a*b*c)
denominator = (d*e*f)
s += (numerator / denominator)
s *= 12
print(1 / s)
Here is my updated code:
import math
def fact(exi):
memory = exi
for i in range(1, exi):
memory *= i
return memory
k = 17
s = 0
for i in range(1, k):
a = (-1)**i
b = fact(6*i)
c = (545140134*i) + 13591409
d = fact(3*i)
e = (fact(i))**3
f = (3 * i) + 3/2
g = math.pow(640320, f)
num = (a*b*c)
den = (d*e*g)
s += (num / den)
s *= 12
print(1 / s)
I see two mistakes:
When comparing with the formula shown on Wikipedia, it looks like you should use the iteration variable i (named q in the formula) where you currently use k in the loop. In your code k is the upper bound for i.
The exponentiation operator in Python is **, not ^ (which is bitwise XOR).
So I am very unexperienced with Python, I know basically nothing, and our teacher gave us the task to write a code that makes a partial fraction decomposition with this function:
I don't really know how to start or even how to define that function. I tried this at first: `
def function(x):
a = (x^4)-(3*x^2)+x+5
b = (x^11)-(3*x^10)-(x^9)+(7*x^8)-(9*x^7)+(23*x^6)-(11*x^5)-(3*x^4)-(4*x^3)-(32*x^2)-16
return a/b
But our maths script says that we need to split up the denominator and then make a system of equations out of it and solve it.
So I was thinking about defining each part of the function itself and then make a function somehow like a = 7*x and use it like f(x) = b/a^7 if this works but I don't really know. We are unfortunately not allowed to use "apart" which I think is a sympy-function?
Thank you so much in advance!
Sincerely, Phie
Addition: So after a few hours of trying I figured this. But I am very sure that this is not the way to do it. Also it tells me that variable l is not defined in z and I am sure that all the others aren't as well. I don't know what to do.
def function(x):
global a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v
a = (x^4)-(3*x^2)+x+5
b = 11
c = 10
d = 9
e = 8
f = 7
g = 6
h = 5
i = 4
j = 3
k = 2
l = x**b
m = 3*x**c
n = x**d
o = 7*x**e
p = 9*x**f
q = 23*x**g
r = 11*x**h
s = 3*x**i
t = 4*x**j
u = 32*x**k
v = 16
return a/(l-m-n+o-p+q-r-s-t-u-v)
print("We are starting the partial fraction decomposition with this
function: (x^4)-(3*x^2)+x+5 / (x^11)-(3*x^10)-(x^9)+(7*x^8)-(9*x^7)+
(23*x^6)-(11*x^5)-(3*x^4)-(4*x^3)-(32*x^2)-16")
z = l-m-n+o-p+q-r-s-t-u-v
while c >= 0:
c = c-1
z = z-l
while d >= 0:
d = d-1
z = z-m
while e >= 0:
e = e-1
z = z-n
while f >= 0:
f = f-1
z = z+o
while g >= 0:
g = g-1
z = z-p
while h >= 0:
h = h-1
z = z+q
while i >= 0:
i = i-1
z = z-r
while j >= 0:
j = j-1
z = z-s
while k >= 0:
k = k-1
z = z-t
print(z)
Since I just solved this myself, here's some input:
Let poly = function() for your function, although be careful to replace ^ with **. Include both from sympy import * and from sympy.abc import a, b, c, d, e, f, g, h, i, j, k, x.
Using factor(exp) you can find all the roots of your function, use these to define the 11 terms term_1 = a/(x-2), term_2 = b/(x2-)**2, ... , term_6 = (f*x + g)/(x**2 +1), ..., term_8 = (j*x + k)/(x**2 + 1) (you get the gist). Define your_sum = term_1 + ... + term_8, eq = Eq(your_sum, poly)
Define the variable your_sum = sum(term_1, ..., term_8), and use solve_undetermined_coeffs(eq, [a,b, ..., k], x))) to get the result.
Given :
I : a positive integer
n : a positive integer
nth Term of sequence for input = I :
F(I,1) = (I * (I+1)) / 2
F(I,2) = F(I,1) + F(I-1,1) + F(I-2,1) + .... F(2,1) + F(1,1)
F(I,3) = F(I,2) + F(I-1,2) + F(I-2,2) + .... F(2,2) + F(2,1)
..
..
F(I,n) = F(I,n-1) + F(I-1,n-1) + F(I-2,n-1) + .... F(2,n-1) + F(1,n-1)
nth term --> F(I,n)
Approach 1 : Used recursion to find the above :
def recursive_sum(I, n):
if n == 1:
return (I * (I + 1)) // 2
else:
return sum(recursive_sum(j, n - 1) for j in range(I, 0, -1))
Approach 2 : Iteration to store reusable values in a dictionary. Used this dictionary to get the nth term.:
def non_recursive_sum_using_data(I, n):
global data
if n == 1:
return (I * (I + 1)) // 2
else:
return sum(data[j][n - 1] for j in range(I, 0, -1))
def iterate(I,n):
global data
data = {}
i = 1
j = 1
for i in range(n+1):
for j in range(I+1):
if j not in data:
data[j] = {}
data[j][i] = recursive_sum(j,i)
return data[I][n]
The recursion approach is obviously not efficient due to maximum recursion depth. Also the next approach's time and space complexity will be poor.
Is there better way to recurse ? or a different approach than recursion ?
I am curious if we can find a formula for nth term.
You could just cache your recursive results:
from functools import lru_cache
#lru_cache(maxsize=None)
def recursive_sum(I, n):
if n == 1:
return (I * (I + 1)) // 2
return sum(recursive_sum(j, n - 1) for j in range(I, 0, -1))
That way you can get the readability and brevity of the recursive approach without most of the performance issues since the function is only called once for each argument combination (I, n).
Using the usual binomial(n,k) = n!/(k!*(n-k)!), you have
F(I,n) = binomial(I+n, n+1).
Then you can choose the method you like most to compute binomial coefficients.
Here an example:
def binomial(n, k):
numerator = denominator = 1
t = max(k, n-k)
for low,high in enumerate(range(t+1, n+1), 1):
numerator *= high
denominator *= low
return numerator // denominator
def F(I,n): return binomial(I+n, n+1)
The formula for the nth term of the sequence is the one you have already mentioned.
Also rightly so you have identified that it will lead to an inefficient algorithm and stack overflow.
You can look into dynamic programming approach where u calculate F(I,N) just once and just reuse the value.
For example this is how the fibonacci seq is calculated.
[just-example] https://www.geeksforgeeks.org/program-for-nth-fibonacci-number/
You need to find the same pattern and cache the value
I have an example for this here in this small code written in golang
https://play.golang.org/p/vRi-QMj7z2v
the standard DP
One can do a (tiny) bit of math to rewrite your function:
F(i,n) = sum_{k=0}^{i-1} F(i-k, n-1) = sum_{k=1}^{i} F(k, n-1)
Now notice, that if you consider a matrix F_{ixn}, to compute F(i,n) we just need to add the elements of the previous column.
x----+---
| + |
|----+ |
|----+-F(i,n)
We conclude that we can build the first layer (aka column). Then the second one. And so forth until we get to the n-th layer.
Finally we take the last element of our final layer which is F(i,n)
The computation time is about O(I*n)
More math based but faster
An other way is to consider our layer as a vector variable X.
We can write the recurrence relation as
X_n = MX_{n-1}
where M is a triangular matrix with 1 in the lower part.
We then want to compute the general term of X_n so we want to compute M^n.
By following Yves Daoust
(I just copy from the link above)
Coefficients should be indiced _{n+1} and _n, but here it is _1 and '' for readability
Moreover the matrix is upper triangular but we can just take the transpose afterwards...
a_1 b_1 c_1 d_1 1 1 1 1 a b c d
a_1 b_1 c_1 = 0 1 1 1 * 0 a b c
a_1 b_1 0 0 1 1 0 0 a b
a_1 0 0 0 1 0 0 0 a
by going from last row to first:
a = 1
from b_1 = a+b = 1 + b = n, b = n
from c_1 = a+b+c = 1+n+c, c = n(n+1)/2
from d_1 = a+b+c+d = 1+n+n(n+1)/2 +d, d = n(n+1)(n+2)/6
I have not proved it but I hint that e_1 = n(n+1)(n+2)(n+3)/24 (so basically C_n^k)
(I think the proof lies more in the fact that F(i,n) = F(i,n-1) + F(i-1,n) )
More generally instead of taking variables a,b,c... but X_n(0), X_n(1)...
X_n(0) = 1
X_n(i) = n*...*(n+i-1) / i!
And by applying recusion for computing X:
X_n(0) = 1
X_n(i) = X_n(i-1)*(n+i-1)/i
Finally we deduce F(i,n) as the scalar product Y_{n-1} * X_1 where Y_n is the reversed vector of X_n and X_1(n) = n*(n+1)/2
from functools import lru_cache
#this is copypasted from schwobaseggl
#lru_cache(maxsize=None)
def recursive_sum(I, n):
if n == 1:
return (I * (I + 1)) // 2
return sum(recursive_sum(j, n - 1) for j in range(I, 0, -1))
def iterative_sum(I,n):
layer = [ i*(i+1)//2 for i in range(1,I+1)]
x = 2
while x <= n:
next_layer = [layer[0]]
for i in range(1,I):
#we don't need to compute all the sum everytime
#take the previous sum and add it the new number
next_layer.append( next_layer[i-1] + layer[i] )
layer = next_layer
x += 1
return layer[-1]
def brutus(I,n):
if n == 1:
return I*(I+1)//2
X_1 = [ i*(i+1)//2 for i in range(1, I+1)]
X_n = [1]
for i in range(1, I):
X_n.append(X_n[-1] * (n-1 + i-1) / i )
X_n.reverse()
s = 0
for i in range(0, I):
s += X_1[i]*X_n[i]
return s
def do(k,n):
print('rec', recursive_sum(k,n))
print('it ', iterative_sum(k,n))
print('bru', brutus(k,n))
print('---')
do(1,4)
do(2,1)
do(3,2)
do(4,7)
do(7,4)
I'm trying a challenge. The idea is the following:
"Your task is to construct a building which will be a pile of n cubes.
The cube at the bottom will have a volume of n^3, the cube above will
have volume of (n-1)^3 and so on until the top which will have a
volume of 1^3.
You are given the total volume m of the building. Being given m can
you find the number n of cubes you will have to build? If no such n
exists return -1"
I saw that apparently:
2³ + 1 = 9 = 3² and 3 - 1 = 2
3³ + 2³ + 1 = 36 = 6² and 6 - 3 = 3
4³ + 3³ + 2³ + 1 = 100 = 10² and 10 - 6 = 4
5³ + 4³ + 3³ + 2³ + 1 = 225 = 15² and 15 - 10 = 5
6³ + 5³ + 4³ + 3³ + 2³ + 1 = 441 = 21² and 21 - 15 = 6
So if I thought, if I check that a certain number is a square root I can already exclude a few. Then I can start a variable at 1 at take that value (incrementing it) from the square root. The values will eventually match or the former square root will become negative.
So I wrote this code:
def find_nb(m):
x = m**0.5
if (x%1==0):
c = 1
while (x != c and x > 0):
x = x - c
c = c + 1
if (x == c):
return c
else:
return -1
return -1
Shouldn't this work? What am I missing?
I fail a third of the sample set, per example: 10170290665425347857 should be -1 and in my program it gives 79863.
Am I missing something obvious?
You're running up against a floating point precision problem. Namely, we have
In [101]: (10170290665425347857)**0.5
Out[101]: 3189089316.0
In [102]: ((10170290665425347857)**0.5) % 1
Out[102]: 0.0
and so the inner branch is taken, even though it's not actually a square:
In [103]: int((10170290665425347857)**0.5)**2
Out[103]: 10170290665425347856
If you borrow one of the many integer square root options from this question and verify that the sqrt squared gives the original number, you should be okay with your algorithm, at least if I haven't overlooked some corner case.
(Aside: you've already noticed the critical pattern. The numbers 1, 3, 6, 10, 15.. are quite famous and have a formula of their own, which you could use to solve for whether there is such a number that works directly.)
DSM's answer is the one, but to add my two cents to improve the solution...
This expression from Brilliant.org is for summing cube numbers:
sum of k**3 from k=1 to n:
n**2 * (n+1)**2 / 4
This can of course be solved for the total volume in question. This here is one of the four solutions (requiring both n and v to be positive):
from math import sqrt
def n(v):
return 1/2*(sqrt(8*sqrt(v) + 1) - 1)
But this function also returns 79863.0. Now, if we sum all the cube numbers from 1 to n, we get a slightly different result due to the precision error:
v = 10170290665425347857
cubes = n(v) # 79863
x = sum([i**3 for i in range(cubes+1)])
# x = 10170290665425347857, original
x -> 10170290665425347856
I don't know if your answer is correct, but I have another solution to this problem which is waaaay easier
def max_level(remain_volume, currLevel):
if remain_volume < currLevel ** 3:
return -1
if remain_volume == currLevel ** 3:
return currLevel
return max_level(remain_volume - currLevel**3, currLevel + 1)
And you find out the answer with max_level(m, 0). It takes O(n) time and O(1) memory.
I have found a simple solution over this in PHP as per my requirement.
function findNb($m) {
$total = 0;
$n = 0;
while($total < $m) {
$n += 1;
$total += $n ** 3;
}
return $total === $m ? $n : -1;
}
In Python it would be:
def find_nb(m):
total = 0
n = 0
while (total < m):
n = n + 1
total = total + n ** 3
return n if total == m else -1
My inner for loop is not using new values from the outer loop.
What's wrong, and how do I fix it?
import numpy as np
a = 0.0000001
b = 15.
d = 0.1
TOL = 1.0e-6
a1 = []
dd = 0.1
da1 = []
for i in range(0,10):
def f(v):
return np.cosh(d * v) - (1./v) * np.sinh(d * v) - 1.
FA = f(a)
FB = f(b)
for I in range(0,1000):
p = a + (b - a) / 2.0
FP = f(p)
if FA == 0 or (b - a)/2.0 < TOL:
break
I = I + 1
if FA * FP > 0:
a = p
FA = FP
if FA * FP < 0:
b = p
a1.append(p)
da1.append(d)
d = d + dd
print a1
print da1
Here is a second implementation. Variable d shows new values, but the inner loop keeps giving me the same result result, like it is not registering the new d value.
import numpy as np
a = 0.00001
a1 = []
dd = 0.1
da = 1.e-5
d = 0.1
yvs=[]
ds = []
EE = []
while d <= 1.:
dnew = d
print dnew
for i in range(0,1000000):
dnew = d
yv = np.cosh(dnew * a) - (1./a) * np.sinh(dnew * a) - 1.
yvs.append(yv)
a = a + da
a1.append(a)
i = i + 1
for ii in range(0,999999):
As = (a1[ii]+a1[ii+1])/2.
E = -1. * As**2
if yvs[ii]*yvs[ii+1] < 0:
EE.append(E)
print As, E
ii = ii + 1
d = dnew + dd
I deleted my earlier answer; it's not the main problem you're having.
You traced the wrong values: d and dnew do, indeed, change. However, they are not part of the data flow for the values you're worried about.
In the upper program, d depends exclusively on its starting value and increment value, both of them 0.1, and dd doesn't change. p depends exclusively on the values of a and b, which also don't change.
Yes, you do some nice work to compute FA, FB, FP -- but then you hit the bottom of the loop, you don't save them anywhere, and then you overwrite tehm on the next loop.
If the lower program, you have the same problem with As and E: you never change the parameters on which they depend (that's all in yvs, which you never print out), so the outputs are the same on every loop.
Since you are using one- and two-letter variables and haven't documented your code, I don't have a good idea of how to fix this: I have little idea what your program is supposed to do, although it appears to want to converge some computational series.