如何使用 Buffon 的针在 tkinter 中计算圆周率?
How to calculate pi in tkinter using Buffon’s needles?
我知道有很多关于如何使用 Buffon's needles 计算 pi 的教程,但我在 tkinter 中没有找到任何教程。
我是初学者,对于脏代码感到很抱歉,但我会很快引导您完成它。
绘制设置后,它会为线条的起点生成随机的 x1 和 y1 坐标。请注意,我希望线条的长度为 50 个单位。所以我生成了 x_rel
,它可以在 -50 到 50 的范围内。之后使用毕达哥拉斯定理,我计算 y_rel
。它可以随机地变为负数或保持正数。要获得直线的终点坐标,只需将 x_rel
和 x1
相加即可,y 也一样。
为了检测与板上一条起始线的碰撞,我比较了 y1 和 y2 的第一个数字。如果它们相同,则不会发生碰撞(这是有效的,因为棋盘上每条起始线之间的距离为 100)。在计算碰撞次数后,我只计算 pi 并打印出来。但它通常 returns ~2,6。但是我在网上找到的其他像这样的程序可以用这种方式相当准确地计算 pi。我的错误在哪里?
import tkinter as tk
import random
import math
count = 0
class App:
def __init__(self, root):
self.root = root
root.title("PI calculator")
c = tk.Canvas(root, height=700, width=700)
c.pack()
c.create_line(100, 100, 600, 100)
c.create_line(100, 200, 600, 200)
c.create_line(100, 300, 600, 300)
c.create_line(100, 400, 600, 400)
c.create_line(100, 500, 600, 500)
c.create_line(100, 600, 600, 600)
for x in range(100000):
c.create_line(self.generate_coords(), fill="red", width=1.5)
def generate_coords(self):
choices = [1, 0]
x1 = random.randint(100, 600)
y1 = random.randint(100, 600)
x_rel = random.randint(-50, 50)
y_rel = math.sqrt(50**2 - x_rel**2)
if random.choice(choices) == 1:
y_rel = -abs(y_rel)
if random.choice(choices) == 0:
y_rel = abs(y_rel)
x2 = x1 + x_rel
y2 = y1 + y_rel
col = self.detect_collision(y1, y2)
if col == True:
global count
count += 1
return x1, y1, x2, y2
def detect_collision(self, y1, y2):
first_num_1 = math.floor(y1/100)
first_num_2 = math.floor(y2 / 100)
if first_num_1 != first_num_2:
return True
else:
return False
root = tk.Tk()
window = App(root)
pi = (2*50*100000)/(100*count)
print(count)
print(pi)
root.mainloop()
38243
2.6148576210025363
我研究了您的代码并将其与类似程序进行了比较,我得出的结论是您的引脚掉落并不像应有的那样随机,这会扭曲您的结果。下面我重新设计了掉针逻辑,结果似乎有所改善:
import tkinter as tk
import random
import math
NUMBER_STICKS = 250
LINE_DISTANCE = 100
STICK_LENGTH = 83
class App:
def __init__(self, root):
self.root = root
root.title("PI calculator")
self.collisions = 0
c = tk.Canvas(root, height=700, width=700)
c.pack()
for y in range(1, 7):
c.create_line(100, y * LINE_DISTANCE, 600, y * LINE_DISTANCE)
for _ in range(NUMBER_STICKS):
collision, *coords = self.generate_coords()
c.create_line(coords, fill="red" if collision else "green", width=1.5)
def generate_coords(self):
x1 = random.randint(100, 600)
y1 = random.randint(100, 600)
angle = random.randrange(360)
x2 = x1 + STICK_LENGTH * math.cos(math.radians(angle))
y2 = y1 + STICK_LENGTH * math.sin(math.radians(angle))
collision = self.detect_collision(y1, y2)
if collision:
self.collisions += 1
return collision, x1, y1, x2, y2
def detect_collision(self, y1, y2):
num_1 = y1 // LINE_DISTANCE
num_2 = y2 // LINE_DISTANCE
return num_1 != num_2
def get_collisions(self):
return self.collisions
root = tk.Tk()
application = App(root)
collisions = application.get_collisions()
print((2 * STICK_LENGTH * NUMBER_STICKS) / (LINE_DISTANCE * collisions))
root.mainloop()
输出
% python3 test.py
3.516949152542373
%
我还修改了程序,将引脚颜色标记为交叉或未交叉:
我知道有很多关于如何使用 Buffon's needles 计算 pi 的教程,但我在 tkinter 中没有找到任何教程。
我是初学者,对于脏代码感到很抱歉,但我会很快引导您完成它。
绘制设置后,它会为线条的起点生成随机的 x1 和 y1 坐标。请注意,我希望线条的长度为 50 个单位。所以我生成了 x_rel
,它可以在 -50 到 50 的范围内。之后使用毕达哥拉斯定理,我计算 y_rel
。它可以随机地变为负数或保持正数。要获得直线的终点坐标,只需将 x_rel
和 x1
相加即可,y 也一样。
为了检测与板上一条起始线的碰撞,我比较了 y1 和 y2 的第一个数字。如果它们相同,则不会发生碰撞(这是有效的,因为棋盘上每条起始线之间的距离为 100)。在计算碰撞次数后,我只计算 pi 并打印出来。但它通常 returns ~2,6。但是我在网上找到的其他像这样的程序可以用这种方式相当准确地计算 pi。我的错误在哪里?
import tkinter as tk
import random
import math
count = 0
class App:
def __init__(self, root):
self.root = root
root.title("PI calculator")
c = tk.Canvas(root, height=700, width=700)
c.pack()
c.create_line(100, 100, 600, 100)
c.create_line(100, 200, 600, 200)
c.create_line(100, 300, 600, 300)
c.create_line(100, 400, 600, 400)
c.create_line(100, 500, 600, 500)
c.create_line(100, 600, 600, 600)
for x in range(100000):
c.create_line(self.generate_coords(), fill="red", width=1.5)
def generate_coords(self):
choices = [1, 0]
x1 = random.randint(100, 600)
y1 = random.randint(100, 600)
x_rel = random.randint(-50, 50)
y_rel = math.sqrt(50**2 - x_rel**2)
if random.choice(choices) == 1:
y_rel = -abs(y_rel)
if random.choice(choices) == 0:
y_rel = abs(y_rel)
x2 = x1 + x_rel
y2 = y1 + y_rel
col = self.detect_collision(y1, y2)
if col == True:
global count
count += 1
return x1, y1, x2, y2
def detect_collision(self, y1, y2):
first_num_1 = math.floor(y1/100)
first_num_2 = math.floor(y2 / 100)
if first_num_1 != first_num_2:
return True
else:
return False
root = tk.Tk()
window = App(root)
pi = (2*50*100000)/(100*count)
print(count)
print(pi)
root.mainloop()
38243
2.6148576210025363
我研究了您的代码并将其与类似程序进行了比较,我得出的结论是您的引脚掉落并不像应有的那样随机,这会扭曲您的结果。下面我重新设计了掉针逻辑,结果似乎有所改善:
import tkinter as tk
import random
import math
NUMBER_STICKS = 250
LINE_DISTANCE = 100
STICK_LENGTH = 83
class App:
def __init__(self, root):
self.root = root
root.title("PI calculator")
self.collisions = 0
c = tk.Canvas(root, height=700, width=700)
c.pack()
for y in range(1, 7):
c.create_line(100, y * LINE_DISTANCE, 600, y * LINE_DISTANCE)
for _ in range(NUMBER_STICKS):
collision, *coords = self.generate_coords()
c.create_line(coords, fill="red" if collision else "green", width=1.5)
def generate_coords(self):
x1 = random.randint(100, 600)
y1 = random.randint(100, 600)
angle = random.randrange(360)
x2 = x1 + STICK_LENGTH * math.cos(math.radians(angle))
y2 = y1 + STICK_LENGTH * math.sin(math.radians(angle))
collision = self.detect_collision(y1, y2)
if collision:
self.collisions += 1
return collision, x1, y1, x2, y2
def detect_collision(self, y1, y2):
num_1 = y1 // LINE_DISTANCE
num_2 = y2 // LINE_DISTANCE
return num_1 != num_2
def get_collisions(self):
return self.collisions
root = tk.Tk()
application = App(root)
collisions = application.get_collisions()
print((2 * STICK_LENGTH * NUMBER_STICKS) / (LINE_DISTANCE * collisions))
root.mainloop()
输出
% python3 test.py
3.516949152542373
%
我还修改了程序,将引脚颜色标记为交叉或未交叉: