パズル懇話会で
「球の表面に乱数で点を打つには?」
というのを話題にした。
「3D的に偏りなく打ちたい」。
自分なりの答えを持っていったが、メンバーからいろんな方法を聞いたのでそれをメモ。
(1) 立方体にうってからの
「平面で円の中に乱数をうつときの方法」を話していて、
そこからの流れで白川さんが言及
球が内接する立方体に乱数で点をうつ
球の中に入っているものだけ採用
球の表面に乗るように射影(正規化)する
Retry:
x=rand(); // -1.0~1.0 の乱数
y=rand();
z=rand();
if(x*x+y*y+z*z<=1.0){
// 採用
// 中心から球への射影
// あるいは半径1への正規化
r=sqrt(x*x+y*y+z*z);
rr=1.0/r;
x=x*rr;
y=y*rr;
z=z*rr;
}else{
goto Retry; // やりなおし 捨てる
}
長所:わかりやすい。<<<<<<<<<<<<<<<<<<<<<<<
短所:乱数の振りなおしがある。
(2)正規分布乱数を使っての
飯田さん案。
正規分布を使う。
x=正規分布乱数(); // 0を中心とした正規分布
y=正規分布乱数();
z=正規分布乱数();
// 球の表面にのせる
r=sqrt(x*x+y*y+z*z);
rr=1.0/r;
x=x*rr;
y=y*rr;
z=z*rr;
「x,y,zがそれぞれ正規分布だった場合
3次元としての(x,y,z)も正規分布」なのだと<<<<<<<<<<<
白川さんや飯田さんがそのように言っていた。
長所:乱数振りなおしがない
短所:正規分布乱数を持ってる必要がある
(3) いやいやそんなことしなくても
岩沢さんが示してくれた方法
緯度と経度で考えて
緯度方向の高さで
z=rand(); <<<<※
経度方向の角度で
theta=rand()*PI
x=cos(theta);
y=sin(theta);
で完了だとのこと。
※のところは
「球の表面積と円柱の側面の表面積が同じ」あたりと関係している。
長所:乱数2回で捨てるとこなし。
短所:zとx,yの取り扱いが違うところが数値計算的にはいくらか心配。
↓wolframalphaで描いた球
以上
x,yはsqrt(1-z^2)の掛け算が抜けているのでは?