Игла Бюффона

Расскажу сейчас про одну интересную штучку из теории вероятности, которая называется «игла Бюффона», будем её реализовывать на Icon. Если коротко, то суть в том, что на поле, которое расчерчено либо вертикальными, либо горизонтальными прямыми линиями, расположенными на одинаковом расстоянии R, бросается игла длиной l, причем длина иглы такова, что количество пересечений иглой линий поля (обозначим его, как m) деленное на общее количество бросков (обозначим, как n) равно некоторому числу (обозначим его как p), которое можно считать вероятностью пересечения иглой линий поля. Таким образом, p = m/n.

Но самое интересное в том, что вероятность p есть число, которое почти постоянно, и его можно вычислить по довольно простой формуле:

p = (2*l)/(R*pi)

где pi — это число Пи.
Следовательно, этот математический факт из теории вероятности можно использовать как метод вычисления числа Пи, что и было сделано в следующей программке:

link graphics,random
global l,n,m,r,p,pp
procedure main()
local W,i
W:=WOpen("size=500,500")
write("Игла Бюффона")
write("------------")
write("Число бросков?")
n:=read()
l:=50.0
r:=100.0
m:=0

every i:=1 to 4 do {
   DrawLine(0,i*r,500,i*r)
}

every i:=1 to n do {
   m:=m+needle()
   randomize()
}
p:=m/n
pp:=(2*l)/(p*r)
DrawString(400,480,"Result:" || pp)
WDone()
end

procedure needle()
local x,y,d,nx,ny,k,i,j
x:=(?400)+20
y:=?470
d:=?360.0
nx:=x+(50*cos(dtor(d)))
ny:=y+(50*sin(dtor(d)))
j:=[100,200,300,400]
DrawLine(x,y,nx,ny)
if y<ny then k:=1 else k:=-1
every i:=y to ny by k do {
 if i=!j then  {
        Fg("red")
 	DrawLine(x,y,nx,ny)
 	Fg("black")
 	return 1.0
  }
}
end

Программа действует так: сначала строится окно размером 500*500, затем у пользователя запрашивается количество бросков иглы (ввод через консоль) и инициализируется переменная счетчик пересечений, затем чертятся четыре горизонтальных линии, после чего стартует функция needle(), заключенная в цикл подсчета количества пересечений (и вместе с тем, цикл раз за разом бросает иглу).

Процедура needle() генерирует случайные координаты x и y «кончика» иглы, затем генерирует случайный угол поворота всей иглы, а также генерирует nx и ny (т.е. координаты другого конца иглы) и используя полярные координаты, вычерчивает саму иглу.

Стоит заметить, то что функция needle() также возвращает 1 и окрашивает иглу красным, в том случае, если хотя бы одна из y координат иглы равна y координате горизонтальных линий (т.е. в случае возникновения пересечения). Вот собственно и все!

Вот так выглядит результат работы программы:
ig8_0_o
Как видите, 57 бросков и уже хорошее приближение. Однако, опыт получается не всегда, поскольку броски иглы не всегда равновероятны, а в остальном все верно.

Добавить комментарий