Будет ли два миллиона очков в секунду?
Распределение симметрично: нам нужно только определить распределение для одной восьмой части полного круга, а затем скопировать его вокруг других октантов. В полярных координатах совокупное распределение угла Θ для случайного положения ( X , Y ) при значении θ определяется площадью между треугольником ( 0 , 0 ) , ( 1 , 0 ) , ( 1 , tan θ ) и дуга окружности, продолжающаяся от (( r , θ )Θ(X,Y)θ(0,0),(1,0),(1,tanθ) до ( cos θ , sin θ ) . Таким образом, оно пропорционально(1,0)(cosθ,sinθ)
FΘ(θ)=Pr(Θ≤θ)∝12tan(θ)−θ2,
откуда его плотность
fΘ(θ)=ddθFΘ(θ)∝tan2(θ).
Мы можем сделать выборку из этой плотности, используя, скажем, метод отбраковки (который имеет эффективность ).8/π−2≈54.6479%
Условная плотность радиальной координаты пропорциональна r d r между r = 1 и r = sec θ . Это можно сделать с помощью простой инверсии CDF.Rг дрг = 1г = секθ
Если мы сгенерируем независимые выборки , преобразование обратно в декартовы координаты ( x i , y i ) произведет выборку этого октанта. Поскольку выборки являются независимыми, случайное переключение координат создает независимую случайную выборку из первого квадранта, по желанию. (Случайные свопы требуют генерации только одной биномиальной переменной, чтобы определить, сколько реализаций нужно поменять.)( гя,θi)(xi,yi)
Каждая такая реализация требует, в среднем, одной равномерной переменной (для R ) плюс 1 / ( 8 π - 2 ) умножения на две равномерных переменной (для Θ ) и небольшое количество (быстрых) вычислений. Это 4 / ( π - 4 ) ≈ 4,66 вариации на точку (что, конечно, имеет две координаты). Полная информация приведена в примере кода ниже. Эта цифра показывает 10000 из более чем полумиллиона сгенерированных очков.(X,Y)R1/(8π−2)Θ4/(π−4)≈4.66
Вот R
код, который произвел это моделирование и рассчитал его.
n.sim <- 1e6
x.time <- system.time({
# Generate trial angles `theta`
theta <- sqrt(runif(n.sim)) * pi/4
# Rejection step.
theta <- theta[runif(n.sim) * 4 * theta <= pi * tan(theta)^2]
# Generate radial coordinates `r`.
n <- length(theta)
r <- sqrt(1 + runif(n) * tan(theta)^2)
# Convert to Cartesian coordinates.
# (The products will generate a full circle)
x <- r * cos(theta) #* c(1,1,-1,-1)
y <- r * sin(theta) #* c(1,-1,1,-1)
# Swap approximately half the coordinates.
k <- rbinom(1, n, 1/2)
if (k > 0) {
z <- y[1:k]
y[1:k] <- x[1:k]
x[1:k] <- z
}
})
message(signif(x.time[3] * 1e6/n, 2), " seconds per million points.")
#
# Plot the result to confirm.
#
plot(c(0,1), c(0,1), type="n", bty="n", asp=1, xlab="x", ylab="y")
rect(-1, -1, 1, 1, col="White", border="#00000040")
m <- sample.int(n, min(n, 1e4))
points(x[m],y[m], pch=19, cex=1/2, col="#0000e010")