Sürekli ağırlıklı rasgele dağılım, bir uca doğru eğilimli


28

Şu anda oyunumuz için bir parçacık sistemine katkıda bulunuyorum ve bazı yayıcı şekiller geliştiriyorum.

Bir çizgi boyunca veya dikdörtgen alan boyunca düzgün rastgele dağılımım iyi çalışıyor - sorun değil.

Ama şimdi bu dağılımda 1 boyutlu bir gradyan gibi bir şeye sahip olmak istiyorum. Bu, örneğin düşük değerlerin yüksek değerlerden daha yaygın olduğu anlamına gelir.

Bu problem için neyin uygun matematiksel terimler olacağını bilmiyorum, bu yüzden arama becerilerim bununla oldukça işe yaramaz. Parçacık sisteminin verimli olması gerektiğinden, hesaplama açısından basit olan bir şeye ihtiyacım var.



Kimse matematikten bahsetmeyecek mi?
Alec Teal

Yanıtlar:


42

Şu resme bir bak:

Eğri eşlemesi

Bir (rastgele) değerin bir eğriye eşlenmesi sürecini gösterir. Diyelim ki 0 ile 1 arasında değişen, düzgün dağılmış rastgele bir X değeri ürettiğinizi varsayalım. .

Bu resimde, ilk eğri daha yüksek değerleri daha olası kılar; ikincisi daha düşük değerleri daha olası kılar; Üçüncüsü, değerleri ortada kümelendiriyor. Eğrinin tam formülü gerçekten önemli değildir ve istediğiniz gibi seçilebilir.

Örneğin, ilk eğri biraz karekök ve ikinci - kareye benziyor. Üçüncüsü biraz küp gibidir, sadece çevrilmiştir. Karekökün çok yavaş olduğunu düşünüyorsanız, ilk eğri de f (X) = 1- (1-X) ^ 2 - karenin ters çevrilmesi şeklinde görünür. Veya bir abanoz: f (X) = 2X / (1 + X).

Dördüncü bir eğride gösterildiği gibi, önceden hesaplanmış bir arama tablosu kullanabilirsiniz. Bir eğri gibi çirkin görünüyor, ama muhtemelen bir parçacık sistemi için yeterince iyi olacak.

Bu genel teknik çok basit ve güçlü. Hangi dağılıma ihtiyacınız olursa olsun, sadece bir eğri haritası hayal edin ve zaman kaybetmeden bir formül tasarlayın. Veya, motorunuzda bir editör varsa, sadece eğri için görsel bir editör yapın!


çok ayrıntılı ve anlaşılır bir açıklama için çok teşekkür ederim. diğer tüm yayınlar da çok yardımcı oldu, ancak yayınınızı en kolay ve en hızlı şekilde anlayabiliyordum. bir şeyleri anlayabilmem için gerçekten önemli bir yere gitti. ve açıkladığınız yönler tam olarak aradığım şeydi (ya da dolaşıyorsunuz)! Gelecekte birçok durumda bunu kullanmamı sağlayacak. yani tekrar thx !!! BTW, eğrilerinizden bazılarıyla oynadım ve çekicilik gibi çalışır.
didito

5
Bilginize: Bunlara niceliksel işlevler denir: en.wikipedia.org/wiki/Quantile_function
Neil G

8

Daha uzun bir açıklama:

@Didito gradient için istediğiniz olasılık dağılımına sahipseniz, fonksiyon olarak tanımlayabilirsiniz. Diyelim ki 0'da olasılık olasılığı 0 olan ve 0'dan 1'e rasgele bir sayı seçmek istediğiniz üçgen dağılımını istediğinizi varsayalım. Bunu y = x olarak yazabiliriz.

Bir sonraki adım bu fonksiyonun integralini hesaplamaktır. Bu durumda, . 0 ile 1 arasında değerlendirildi, bu ½. Bu mantıklı - bu taban 1 ve yükseklik 1 olan bir üçgen, yani alanı ½.x=1x2

Daha sonra 0'dan bölgeye eşit olarak rastgele bir nokta seçersiniz (örneğimizde ½). Diyelim ki bu z. ( Kümülatif dağılımdan eşit olarak toplanıyoruz .)

Bir sonraki adım geriye doğru gitmek, x'in (x olarak adlandırırız) değerinin z alanına karşılık geldiğini bulmaktır. Biz için ideal z eşittir 0 ile x değerlendirilir. İçin çözmek , olsun .x=1x21x̂2=zx̂=2z

Bu örnekte, z'yi 0'dan ½'ye seçersiniz ve ardından istediğiniz rasgele sayı . Basitleştirilmiş, - tam olarak ne eBusiness'ın önerdiği gibi yazabilirsiniz .2zrand(0,1)


değerli girişiniz için teşekkürler. Ben her zaman yetenekli insanların problemleri nasıl çözdüklerini duymayı severim ama dürüst olmak gerekirse hala kafamı etrafına
sarmam

bu harika. sqrt(random())Hayatım boyunca hep yaptım ama ampirik olarak geldim. Rasgele bir sayıyı bir eğriye bağlamaya çalışıyor ve işe yaradı. Şimdi biraz daha matematik becerisine sahip olduğuma göre, neden işe yaradığını bilmek çok değerli!
Gustavo Maciel

5

Üstel bir sistemi kullanarak, muhtemelen istediklerine yakın bir yaklaşım elde edersin.

X'i 1- (rnd ^ değeri) gibi bir şeye göre yapın (rnd'nin 0 ile 1 arasında olduğunu varsayalım) ve kullandığınıza bağlı olarak soldan sağa doğru eğilme ile ilgili birkaç farklı davranış elde edersiniz. Daha yüksek bir değer, size daha fazla eğik dağılım sağlar

Farklı denklemlerin onları yerleştirmeden önce size sağlayacağı davranışlar hakkında bazı kaba fikirler almak için çevrimiçi bir grafik aracı kullanabilirsiniz veya zevklerinize hangi stilin daha fazla olduğuna bağlı olarak denklemleri doğrudan parçacık sisteminizle oynatabilirsiniz.

DÜZENLE

Parçacık başına CPU zamanının çok önemli olduğu bir parçacık sistemi gibi bir şey için, Math.Pow (ya da dil eşdeğeri) kullanmak doğrudan performansın düşmesine neden olabilir. Daha fazla performans isteniyorsa ve çalışma zamanında değer değişmiyorsa, x ^ 2 yerine x * x gibi eşdeğer bir işleve geçmeyi düşünün.

(Kesirli üsteller daha fazla sorun olabilir, ancak benim tahmin ettiğimden daha güçlü bir matematik geçmişine sahip olan biri, bir yaklaşım fonksiyonu oluşturmak için iyi bir yol bulabilirdi)


1
Bir grafik programı kullanmak yerine, Beta dağılımını sadece özel bir durum olduğu için çizebilirsiniz. Verilen için valuebu Beta (değer, 1).
Neil G

Teşekkürler. bazı grafikler çizmeyi denedim ve beni istediğim yere getirebileceğini düşünüyorum.
didito

@Neil G "beta dağıtımı" ipucuna teşekkür ediyor - bu ilginç ve faydalı görünüyor ... bu konuda biraz araştırma yapacağım
didito

3

Aradığınız terim Weighted Random Numbers, gördüğüm algoritmaların çoğu trig işlevlerini kullanıyor, ancak verimli olacak bir yol buldum.

Rasgele işlev için çarpan değerini tutan bir tablo / dizi / Liste (ne olursa olsun) oluşturun. Elle ya da programlı olarak doldurun ...

randMulti= {.1,.1,.1,.1,.1,.1,.2,.2,.3,.3,.9,1,1,1,} 

... daha sonra randomrastgele seçilen randMultive sonunda dağılımın maksimum değeri ile çarpın ...

weightedRandom = math.random()*randMulti[Math.random(randMulti.length)]*maxValue

Bunun kullanımdan çok daha hızlı olacağına sqrtya da diğer karmaşık hesaplama fonksiyonlarına ve daha fazla özel gruplama düzenine izin vereceğine inanıyorum.


2
Belleği feda edebilirsiniz, önceden hesaplanmış 100 değerden oluşan bir tablo daha hızlı (ve biraz daha doğru) olacaktır. Kullanıcının, tam ve önceden hesaplanmış versiyonları birbirinden ayırabileceğinden şüpheliyim.
Daniel Blezek

@Daniel daha hızlı olurdu, ancak 100 rastgele değerle, yinelenen kalıpları görmek oldukça kolaydır.
AttackHobo

Sırf tekrarlayan bir model olduğu görülmesi, rastgele olmadığı anlamına gelmez. Rastgeleğin özü, tahmin edilemezliğidir; bu, kelimenin tam anlamıyla, birinin bir kalıp olmayacağını tahmin edemediği kadar, birinin de (en azından kısa bir süre) olabileceğini tahmin edemediği anlamına gelir. Bazı testler yapmanız gerekecek, ancak farklı tohumlar kullanarak çoklu testler içeren desenler bulursanız, sahte rastgele sayılar üretme algoritmanızın gözden geçirilmesi gerekebilir.
Randolf Richardson

Bu numara için @AttackingHobo thx. AUT kullanımını seviyorum. ve formül anlaşılması oldukça kolaydır. daha önce bu şekilde düşünmedim. ahşabı ağaçlar için görmemek ... :) ayrıca yinelenen kalıplardan da kaçınılması gerektiğini düşünüyorum, ancak yine de bu durumda tanınmayacaklarını düşünüyorum. Yine de, tüm değerleri önceden hesaplamak görsel deneyime zarar verir. Her neyse, bana bunun rastgelelik konusunda göz önünde bulundurulması gereken bir faktör olduğunu hatırlattığım için ...
didito

Ayrıca Ağırlıklı "Rastgele Sayılar" terimini getirdiğiniz için teşekkür ederiz!
didito

2

Sanırım istediğin, kare kök işlevi kullanılarak elde edilen dağılım.

[position] = sqrt(rand(0, 1))

Bu, [0, 1]bir pozisyon olasılığının, o pozisyona eşdeğer olduğu tek bir boyut alanında bir dağılım verecektir , yani bir "üçgen dağılım".

Alternatif karekersiz nesil:

[position] = 1-abs(rand(0, 1)-rand(0, 1))

Optimal uygulamadaki bir kare kökü sadece birkaç çarpma ve dalsız komutlar toplamıdır. (Bkz . Http://en.wikipedia.org/wiki/Fast_inverse_square_root ). Bu iki fonksiyondan hangisinin daha hızlı olduğu platforma ve rasgele üreteçe bağlı olarak değişebilir. Örneğin bir x86 platformunda, ikinci yöntemi yavaşlatmak için rastgele üreteçte yalnızca birkaç öngörülemeyen dal alacaktır.


Bir pozisyonun olasılığı, pozisyona eşit olmaz (matematiksel olarak imkansız olan - önemsiz olarak, fonksiyonun alanı ve aralığı hem 0.50 hem de 0.51'i içerir), ne de üçgen bir dağılımdır. ( en.wikipedia.org/wiki/Triangular_distribution )

1
Sqrt bazı ilginç kalıplar verirken, parçacık sistemlerinin genellikle parçacık başına çok CPU ışığı olması gerekir, bu yüzden mümkünse kareköklerden kaçınılmasını tavsiye ederim. Bazen sadece önceden hesaplama yapmaktan kaçınabilirsiniz, ancak parçacıklarınızın zaman içinde gözle görülür patikaları olmasına neden olabilir.
Lunin

1
@Joe Wreschnig, Wikipedia makalesini kendiniz okudunuz mu, a = 0, b = 1, c = 1 kodunu jenerasyon formülüne yazdınız ve formülü yazıma aldınız.
aaaaaaaaaaaa

3
@Lunin, cevabında bir üs varken neden karekökten şikayet ediyorsun?
aaaaaaaaaaaa

1
@Lunin: Performans teorisi oldukça ihmal edilmiş bir alandır, insanların ALU'ların büyük pahalı ve yavaş olduğu yaklaşık 30 yıl önce nerede doğru olduklarını bildiklerini sandıklarının çoğu. Oldukça yavaş bir aritmetik işlevi olduğunu keşfettiğiniz üs fonksiyonu bile nadiren oldukça önemli bir performans günahkardır. Dallanma (bir if ifadesi kullanarak) ve önbellek özlüyor (şu anda önbellekte bulunmayan bir veri parçasını okumak), genellikle en yüksek maliyete mal oluyor.
aaaaaaaaaaaa 24:11

1

Sadece bir Beta dağıtımı kullanın:

  • Beta (1,1) düz
  • Beta (1,2) doğrusal bir gradyandır
  • Beta (1,3) ikinci dereceden

vb.

İki şekil parametresinin tamsayı olması gerekmez.


yardımınız için teşekkürler. Yukarıda belirtildiği gibi, beta dağılımı ilginç geliyor. ancak henüz wikipedia sayfasının içeriğini anlamıyorum. veya bir formül / kod. Ayrıca, şu an daha fazla araştırma yapmak için zamanım yok: si, artırmanın beta dağıtımları için kodunun olduğunu görüyor, ancak bu fazlaca olacaktır. iyi, sanırım önce geçip sonra kendi basitleştirilmiş versiyonumu yazmam gerekiyor.
didito

1
@ didito: Çok zor değil. Siz sadece uniform_generator()aramanızı değiştirin gsl_ran_beta(rng, a, b). Buraya bakın: gnu.org/software/gsl/manual/html_node/…
Neil G

ipucu için thx. GSL kullanmıyorum (daha önce hiç duymadım), ama iyi görüşme. kaynağı kontrol edeceğim!
didito

@ didito: Bu durumda, Lunin'in çözümüyle giderdim. İyi şanslar.
Neil G

0

Daha da basit, rastgele jeneratörünüzün hızına bağlı olarak, sadece iki değer üretebilir ve ortalamalarını alabilirsiniz.

Ya da, daha basit, X ilk RNG, sonucudur nerede double y = double(1/x);, x = y*[maximum return value of rng];. Bu sayıları katlanarak düşük sayılar için ağırlıklandırır.

Değerleri merkeze yaklaştırma olasılığını artırmak için daha fazla değer üretin ve ortalayın.

Elbette bu sadece standart çan eğrileri dağılımları veya "katlanmış" versiyonları için işe yarar *, ancak hızlı bir jeneratör ile, sqrt gibi çeşitli matematik fonksiyonlarını kullanmaktan daha hızlı ve basit olabilir.

Zar çan eğrileri için bu konuda her türlü araştırmayı bulabilirsiniz. Aslında, Anydice.com çeşitli yuvarlanma zarları için grafikler üreten iyi bir sitedir. Bir RNG kullanıyor olsanız da, öncül sonuçlar gibi aynıdır. Bu yüzden, kodlamadan önce bile dağıtımı görmek için iyi bir yer.

* Ayrıca, ekseni alarak ve ortalama sonucu çıkardıktan sonra ekseni ekleyerek sonuç dağılımını bir eksen boyunca "katlayabilirsiniz". Örneğin, daha düşük değerlerin daha yaygın olmasını istersiniz ve en düşük değeriniz 15, en büyük değeriniz 35, en yüksek değeriniz 20 olsun, diyelim ki 20 aralığındaki iki değeri üretir ve ortalarsınız. İstediğiniz mesafenin iki katı), ki bu 20 merkezli bir çan kulesi verecektir (aralığı 20'den 40'a, 15'ten 35'e kadar kaydırmak için sonunda beşi çıkardık). Oluşturulan X ve Y sayılarını alın.

Son numara

z =(x+y)/2;// average them
If (z<20){z = (20-z)+20;}// fold if below axis
return z-5;// return value adjusted to desired range

Eğer sıfır sizin minimumunuzsa, daha iyisi yerine, bunu yapın.

z= (x+y)/2;
If (z<20){z = 20-z;}
else {z = z - 20;}
return z;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.