I'm trying to write a program in Python that estimates pi, but to get a more accurate estimation in a feasible amount of time, I want to make it faster.
I'm using a method that estimates the area of the circle by counting all the coordinates that land inside of a circle with radius r and dividing that result by r**2 to get pi. So far to speed it up, I've:
- cut the count requirement in quarter by only using a quarter of the circle (the upper right quarter)
- skipping chunks of each row if both ends are inside the circle only starting from the previous position instead of restarting from 0
- starting from halfway down the arc and disregarding the big square in the middle from the count (only counts about 30% of the quarter circle but uses it to work out the rest)
So far I've got it to effectively work out 100 trillion coordinates (radius of 10,000,000) in ~15 seconds and yielding 11 correct digits. This is cut down to ~13 seconds if you remove the progress check print statements. Below is my code, please help in any way to optimize. It is greatly appreciated.
from time import time
r = 10000000
rs = r**2
aCount = 0
prevy = 8008135
prevTime = "meow"
#=============================================#
y = 0.5 * r
x = 0.5 * r
prevX = x
while x**2 + y**2 <= rs:
if (x*1.00001)**2 + (y*1.00001)**2 <= rs:
x = int(x*1.0001) # move up from the origin at a 45 degree angle to find
y = int(y*1.0001) # the middle of the arc
x+=1
y+=1
if x == prevX:
break
prevX = x
#=============================================#
startX = x
start = time()
endX = 0
while y > 0:
if int(time()) != prevTime:
print(f"{(int((-y/r)*100))+100}% complete, {-int((y/(y-prevy))/2)} Seconds to go [{-(y-prevy)}]")
prevy = y
prevTime = int(time())
ys = y**2
aCount += ((x - 1) - startX)
while x <= r:
xs = x**2
if xs + ys > rs:
break
if xs + ys <= rs and (x+99999)**2 + ys <= rs:
aCount += 100000
x += 100000
elif xs + ys <= rs and (x+9999)**2 + ys <= rs:
aCount += 10000
x += 10000
elif xs + ys <= rs and (x+999)**2 + ys <= rs:
aCount += 1000
x += 1000
elif xs + ys <= rs and (x+99)**2 + ys <= rs:
aCount += 100
x += 100
elif xs + ys <= rs and (x+9)**2 + ys <= rs:
aCount += 10
x += 10
elif xs + ys <= rs:
aCount += 1
x += 1
else:
x += 1
endX = x
y -= 1
aCount *= 2 #work out the quarter using the right-most fragment (see diagram)
aCount += startX ** 2 #add the missing square between the two fragments
aCount *= 2 #double the quarter circle and add the y=0 (where x is greater than 0) line
aCount += r
aCount *= 2 #double the half circle and add the x=0 (where y is greater than or less than 0) line
aCount += 2*r + 1 #then add the (0,0) point for the full area
print(aCount/(rs))
print("That took "+str(int(time()-start))+" seconds")