Math formula python interpretation - python

I've been trying to convert this math formula into python.
So basically the approximation of 1/math.pi.
I tried making this iteration with
import math
N = 132
for k in range(1, N+1):
print("The N value is",N , end="\r", flush=True)
rec_pi_approximate = (2*math.sqrt(2)/9801) * N * ((math.factorial(4*k) * (1103+26390*k))/((math.factorial(k)**4) * (396**4*k)))
But my values have been weird and I need guidance on how to actually type the formula and make a summation loop for it. Currently I am trying to find the reciprocal of pi with this formula equivalent to 1/math.pi

The idea with the for loop is that you add up a part of the summation on each iteration. So you should keep track of the total sum so far and add to it each time. Because of math properties, you can multiply by the constant that’s outside the summation while summing so you don't need to at the end.
import math
N = 132
pi_approximate_inv = 0
for k in range(0, N+1):
print("The N value is", k)
pi_approximate_inv += (2*math.sqrt(2)/9801) * ((math.factorial(4*k) * (1103+26390*k))/((math.factorial(k)**4) * (396**(4*k))))
print("The pi approximate is", 1.0/pi_approximate_inv)
You also missed some parentheses at (396**(4*k)) which I added. Also, it should be print("The N value is", k) (k not N) because it is showing what the result would be if it stopped right there at k.
Because of floating point precision limits, it appears to max out at N=2 (meaning 3 iterations).

Related

my code ends with OverflowError when I have large inputs

One of my homework questions, and I am only allowed to import pi.
The question asks to compute the cosine function by Taylor series, which I have done so far. The outputs I get are correct however when k gets larger than 90, I get OverflowError: int too large to convert to float.
from math import pi
def myCos(angle,k):
total=0
for i in range(k):
total += (((-1)**(i))*((angle*pi/180)**(2*(i))))/(fact(2*(i)))
return total
def fact(n):
if n == 0:
return 1
else:
return fact(n-1)*n
In order to get full marks for this question, the code has to accept k > 100.
i.e
myCos(45,5)
0.7071068056832942
myCos(45,60)
0.7071067811865475
myCos(45,90)
total += (((-1)**(i))*((angle*pi/180)**(2*(i))))/(fact(2*(i)))
OverflowError: int too large to convert to float
Can someone please enlighten me on this?
Your main division in the summation exceeded the range of type float. To do that division, you have to convert the denominator to type float. fact(2*85) is larger than the maximum float value.
Do the operations in a difference order. For instance:
numer = (angle*pi/180)**(2*(i))
for denom in range(1, 2*i + 1):
numer /= denom
Now numer is a reasonable (?) representation of the value desired. If you need better reliability, "chunk" the denominator values and divide by the product of, say, groups of 10 denom values.
def myCos(angle,k):
total=0
for i in range(k):
numer = (angle*pi/180)**(2*(i))
for denom in range(2, 2*i+1):
numer /= denom
total += (-1) ** i * numer
return total
print(myCos(45,5))
print(myCos(45,60))
print(myCos(45,90))
Output:
0.7071068056832942
0.7071067811865475
0.7071067811865475

Newton-raphson script freezes in attempt to root great numbers

I am trying to do square root using newton-raphson algorithm of random numbers given by this formula:
a = m * 10 ^c
where m is random float in range (0,1) and c is random integer in range (-300,300).
Code i wrote works perfectly with precision of root as 0.01 and c in range (-30,30) but freezes or returns wrong results when i use c range given in task.
here is code for newton function
def newton_raphson(a):
iterations_count = 0
x_n_result = a/2
while abs(x_n_result - a / x_n_result) > 0.01:
x_n_result = (x_n_result + a/x_n_result)/2
iterations_count = iterations_count + 1
if x_n_result*x_n_result == a:
break
iterations.append(iterations_count)
results.append(x_n_result)
print("Result of function", x_n_result)
return
and part where numbers to root are randomized
for i in range(0, 100):
m = random.uniform(0, 1)
c = random.randint(-30, 30)
a = m * 10 **c
random_c.append(c)
numbers.append(a)
print("Number to root : ", i, "|", a, '\n')
newton_raphson(a)
plot of the amount of iteration from the value of c
plt.bar(random_c, iterations, color='red')
Script is supposed to root 100 random numbers and then plot amount of iteration required to root number from values of c. Problem is like i said before with proper range of c value. I believe it has to do something with range of variables. Any sugestion how to solve this?
First observation is that your logic will get you a square root, not a cubic root.
The second thing is that your random numbers can contain negative values which will never converge for a square root.
If you really wanted a cubic root, you could do it like this:
def cubic(number):
result = number
while abs(number/result/result - result) > 0.01:
result += (number/result/result - result)/2
return result
you could also approach this in a generic fashion by creating a newton/raphson general purpose function that takes a delta function as parameter to use on a number parameter:
def newtonRaphson(delta,n):
result = n
while abs(delta(n,result)) > 0.01:
result += delta(n,result)/2
return result
def cubic(n,r): return n/r/r - r
def sqrt(n,r): return n/r - r
The use the newtonRaphson method with your chosen delta function:
newtonRaphson(sqrt,25) # 5.000023178253949
newtonRaphson(cubic,125) # 5.003284700817307

Finding the sum of a geometric progression

I'm being asked to add the first 100 terms f the sequence (1 + 1/2 + 1/4 + 1/8 ...etc)
what i ve been trying is something Iike
for x in range(101):
n = ((1)/(2**x))
sum(n)
gives me an error, guess you cant put ranges to a power
print(n)
will give me a list of all the values, but i need them summed together
anyone able to give me a hand?
using qtconsole if that's of any relevance, i'm quite new to this if you haven't already guessed
You keep only one value at a time. If you want the sum, you need to aggregate the results, and for that you'd need an initial value, to which you can add each round the current term:
n = 0 # initial value
for x in range(100):
n += 1 / 2**x # add current term
print(n)
Hmm, there is actually a formula for sum of geometric series:
In your question, a is 1, r is 0.5 and n is 100
So we can do like
a = 1
r = 0.5
n = 100
print(a * (1 - r ** n) / (1 - r))
It is important to initialize sum_n to zero. With each iteration, you add (1/2**x) from your sequence/series to sum_n until you reach n_range.
n_range = 101
sum_n = 0 # initialize sum_n to zero
for x in range(n_range):
sum_n += (1/(2**x))
print(sum_n)
You are getting an error because sum takes an iterable and you are passing it a float:
sum(iterable[, start])
To solve your problem, as others have suggested, you need to init an accumulator and add your power on every iteration.
If you absolutely must use the sum function:
>>> import math
>>> sum(map(lambda x:math.pow(2,-x),range(100)))
2.0

Optimizing Totient function

I'm trying to maximize the Euler Totient function on Python given it can use large arbitrary numbers. The problem is that the program gets killed after some time so it doesn't reach the desired ratio. I have thought of increasing the starting number into a larger number, but I don't think it's prudent to do so. I'm trying to get a number when divided by the totient gets higher than 10. Essentially I'm trying to find a sparsely totient number that fits this criteria.
Here's my phi function:
def phi(n):
amount = 0
for k in range(1, n + 1):
if fractions.gcd(n, k) == 1:
amount += 1
return amount
The most likely candidates for high ratios of N/phi(N) are products of prime numbers. If you're just looking for one number with a ratio > 10, then you can generate primes and only check the product of primes up to the point where you get the desired ratio
def totientRatio(maxN,ratio=10):
primes = []
primeProd = 1
isPrime = [1]*(maxN+1)
p = 2
while p*p<=maxN:
if isPrime[p]:
isPrime[p*p::p] = [0]*len(range(p*p,maxN+1,p))
primes.append(p)
primeProd *= p
tot = primeProd
for f in primes:
tot -= tot//f
if primeProd/tot >= ratio:
return primeProd,primeProd/tot,len(primes)
p += 1 + (p&1)
output:
totientRatio(10**6)
16516447045902521732188973253623425320896207954043566485360902980990824644545340710198976591011245999110,
10.00371973209101,
55
This gives you the smallest number with that ratio. Multiples of that number will have the same ratio.
n = 16516447045902521732188973253623425320896207954043566485360902980990824644545340710198976591011245999110
n*2/totient(n*2) = 10.00371973209101
n*11*13/totient(n*11*13) = 10.00371973209101
No number will have a higher ratio until you reach the next product of primes (i.e. that number multiplied by the next prime).
n*263/totient(n*263) = 10.041901868473037
Removing a prime from the product affects the ratio by a proportion of (1-1/P).
For example if m = n/109, then m/phi(m) = n/phi(n) * (1-1/109)
(n//109) / totient(n//109) = 9.91194248684247
10.00371973209101 * (1-1/109) = 9.91194248684247
This should allow you to navigate the ratios efficiently and find the numbers that meed your need.
For example, to get a number with a ratio that is >= 10 but closer to 10, you can go to the next prime product(s) and remove one or more of the smaller primes to reduce the ratio. This can be done using combinations (from itertools) and will allow you to find very specific ratios:
m = n*263/241
m/totient(m) = 10.000234225865265
m = n*(263...839) / (7 * 61 * 109 * 137) # 839 is 146th prime
m/totient(m) = 10.000000079805726
I have a partial solution for you, but the results don't look good.. (this solution may not give you an answer with modern computer hardware (amount of ram is limiting currently)) I took an answer from this pcg challenge and modified it to spit out ratios of n/phi(n) up to a particular n
import numba as nb
import numpy as np
import time
n = int(2**31)
#nb.njit("i4[:](i4[:])", locals=dict(
n=nb.int32, i=nb.int32, j=nb.int32, q=nb.int32, f=nb.int32))
def summarum(phi):
#calculate phi(i) for i: 1 - n
#taken from <a>https://codegolf.stackexchange.com/a/26753/42652</a>
phi[1] = 1
i = 2
while i < n:
if phi[i] == 0:
phi[i] = i - 1
j = 2
while j * i < n:
if phi[j] != 0:
q = j
f = i - 1
while q % i == 0:
f *= i
q //= i
phi[i * j] = f * phi[q]
j += 1
i += 1
#divide each by n to get ratio n/phi(n)
i = 1
while i < n: #jit compiled while loop is faster than: for i in range(): blah blah blah
phi[i] = i//phi[i]
i += 1
return phi
if __name__ == "__main__":
s1 = time.time()
a = summarum(np.zeros(n, np.int32))
locations = np.where(a >= 10)
print(len(locations))
I only have enough ram on my work comp. to test about 0 < n < 10^8 and the largest ratio was about 6. You may or may not have any luck going up to larger n, although 10^8 already took several seconds (not sure what the overhead was... spyder's been acting strange lately)
p55# is a sparsely totient number satisfying the desired condition.
Furthermore, all subsequent primorial numbers are as well, because pn# / phi(pn#) is a strictly increasing sequence:
p1# / phi(p1#) is 2, which is positive. For n > 1, pn# / phi(pn#) is equal to pn-1#pn / phi(pn-1#pn), which, since pn and pn-1# are coprime, is equal to (pn-1# / phi(pn-1#)) * (pn/phi(pn)). We know pn > phi(pn) > 0 for all n, so pn/phi(pn) > 1. So we have that the sequence pn# / phi(pn#) is strictly increasing.
I do not believe these to be the only sparsely totient numbers satisfying your request, but I don't have an efficient way of generating the others coming to mind. Generating primorials, by comparison, amounts to generating the first n primes and multiplying the list together (whether by using functools.reduce(), math.prod() in 3.8+, or ye old for loop).
As for the general question of writing a phi(n) function, I would probably first find the prime factors of n, then use Euler's product formula for phi(n). As an aside, make sure to NOT use floating-point division. Even finding the prime factors of n by trial division should outperform computing gcd n times, but when working with large n, replacing this with an efficient prime factorization algorithm will pay dividends. Unless you want a good cross to die on, don't write your own. There's one in sympy that I'm aware of, and given the ubiquity of the problem, probably plenty of others around. Time as needed.
Speaking of timing, if this is still relevant enough to you (or a future reader) to want to time... definitely throw the previous answer in the mix as well.

How do I optimize an algorithm to decompose a number as the sum of two squares?

I have a simple math algo. All it does is it takes an input and finds i,j such that i^2 + j^2 = input with the restriction that j >= i (so that it doesn't print it's counterpart e.g., 2^2 + 3^2 == 3^2 + 2^2 but I only need the latter as j >= i)
For my code, I did the following: I have 2 for loops, first loop for i and second loop for j. Takes both i and j values and test if i^2 + j^2 == input and if j >= i. if yes, print it and update count.
The problem is, with large sums of values, it takes a very long time as it loops twice from 1 to 2000 and then 1 to 2000 again.
def some_mathfn(n):
count = 0
for i in range(1,n+1):
for j in range(1,n+1):
if(i**2 + j**2 == n and j >= i):
g = print(i, '^2 + ', j,'^2')
count += 1
return count
some_mathfn(2001)
You've got an O(n2) algorithm for no obvious reason. It's easy to make this O(n1/2)...
Loop from 1 to the square root of n/2 (for variable i) - because when i is greater than sqrt(n/2) then i*i + j*j will be greater than n for any j greater than i.
(Only to the square root of n, because
Subtract the square of i
Take the square root of the result, and find the nearest integer - call that j
Check whether the condition you're interested in holds
The last two steps are effectively just checking that the square root of n - i*i is actually an integer, but in some cases (for very large values of n) finding the nearest integer and then checking the condition could be a more reliable approach, in order to avoid floating point limitations causing issues, where the nearest-representable double to the theoretical result could be an integer, despite that actual result not being an integer. This would only happen for really large values of n, but...

Categories