Rand ()% 6 neden önyargılıdır?


109

Std :: rand'ın nasıl kullanılacağını okurken, bu kodu cppreference.com'da buldum

int x = 7;
while(x > 6) 
    x = 1 + std::rand()/((RAND_MAX + 1u)/6);  // Note: 1+rand()%6 is biased

Sağdaki ifadenin nesi yanlış? Denedim ve mükemmel çalışıyor.


24
Zar için kullanmanın daha da iyi olduğuna dikkat edinstd::uniform_int_distribution
Caleth

1
@Caleth Evet, sadece bu kodun neden 'yanlış' olduğunu anlamak
içindi

15
"Yanlış" "önyargılı" olarak değiştirildi
Cubbi

3
rand()tipik uygulamalarda çok kötüdür, xkcd RNG'yi de kullanabilirsiniz . Yani yanlış çünkü kullanıyor rand().
CodesInChaos

3
Bu şeyi yazdım (yorum değil - bu @Cubbi) ve o sırada aklımda olan şey, Pete Becker'in cevabının açıkladığı şeydi . (Bilginize, bu temelde libstdc ++ 'larla aynı algoritmadır uniform_int_distribution.)
TC

Yanıtlar:


136

İle ilgili iki sorun vardır rand() % 6(bu 1+iki sorunu da etkilemez).

İlk olarak, birkaç yanıtın işaret ettiği gibi, eğer düşük bitler rand()uygun şekilde tekdüze değilse, kalan operatörün sonucu da aynı değildir.

İkinci olarak, tarafından üretilen farklı değerlerin sayısı rand()6'nın katı değilse, geri kalan yüksek değerlerden daha düşük değerler üretecektir. rand()Mükemmel dağıtılmış değerler döndürse bile bu doğrudur .

Uç bir örnek olarak, rand()aralıkta eşit dağılmış değerler ürettiğini varsayalım [0..6]. Bu değerler için kalanlara bakarsanız rand(), aralıkta bir değer döndürdüğünde [0..5], kalan aralıkta tekdüze dağıtılmış sonuçlar üretir [0..5]. Ne zaman rand()döner 6, rand() % 6sadece sanki döndürür 0, rand()diğer değerlerden gibi birçok 0 yılların iki katı olan bir dağılım elde Yani 0'a dönmüştü.

İkincisi, gerçek sorun rand() % 6.

Bu sorunu önlemek için bir yol olduğunu ıskarta düzgün olmayan çiftleri üretecektir değerler. Daha küçük veya eşit olan 6'nın en büyük katını hesaplarsınız ve bu kattan büyük veya ona eşit bir değer döndürdüğünüzde RAND_MAX, rand()onu reddedersiniz ve gerektiğinde tekrar `rand () 'ı çağırırsınız.

Yani:

int max = 6 * ((RAND_MAX + 1u) / 6)
int value = rand();
while (value >= max)
    value = rand();

Bu, söz konusu kodun, neler olup bittiğini daha net bir şekilde göstermeyi amaçlayan farklı bir uygulamasıdır.


2
Bu konuda bir kağıt üretmek için bu sitedeki en az bir düzenli söz verdiler ama bence örnekleme ve ret o olabilir kafayı anları atmak; örneğin varyansı aşırı şişirmek.
Bathsheba

30
Rand_max 32768 ise bu tekniğin ne kadar önyargı getirdiğini gösteren bir grafik yaptım, ki bu bazı uygulamalarda olduğu gibi. ericlippert.com/2013/12/16/…
Eric Lippert

2
@Bathsheba: Bazı reddetme işlevlerinin buna neden olabileceği doğru, ancak bu basit reddetme, tek tip bir IID'yi farklı bir tek tip IID dağılımına dönüştürecek. Hiçbir bit taşınmaz, o kadar bağımsızdır ki, tüm örnekler aynı reddi kullanır, o kadar özdeş ve tekdüzelik göstermek için önemsizdir. Ve tekdüze bir integral rastgele değişkenin daha yüksek momentleri, onun aralığı ile tam olarak tanımlanır.
MSalters

4
@MSalters: İlk cümle için doğru gerçek bir sahte jeneratör için mutlaka doğrudur, jeneratör. Emekli olduğumda bunun üzerine bir makale yazacağım.
Bathsheba

2
@Anthony zar açısından düşünün. 1 ile 3 arasında rastgele bir sayı istiyorsunuz ve yalnızca standart 6 kenarlı bir kalıbınız var. 4-6 atarsanız bunu sadece 3 çıkararak elde edebilirsiniz. Ama bunun yerine 1 ile 5 arasında bir sayı istediğinizi varsayalım. 6 yuvarladığınızda 5 çıkarırsanız, diğer herhangi bir sayıdan iki kat fazla 1 elde edersiniz. Temelde cppreference kodunun yaptığı şey budur. Yapılması gereken doğru şey 6'ları yeniden gözden geçirmek. Pete'in burada yaptığı şey bu: her bir sayıyı yuvarlamanın aynı sayıda yolu olması için kalıbı bölün ve çift bölümlere uymayan sayıları yeniden sıralayın
Ray

19

Burada gizli derinlikler var:

  1. Küçük kullanımı uin RAND_MAX + 1u. RAND_MAXbir inttür olarak tanımlanır ve genellikle mümkün olan en büyüktür int. Bu tür durumlarda, bir türü taşırken davranışı tanımsızRAND_MAX + 1 olacaktır . Yazma güçleri dönüşümünü tip için öylesine taşma obviating.signed1uRAND_MAXunsigned

  2. Kullanımı % 6 kutu (ama her uygulanmasına ilişkin std::randI gördüğüm gelmez yukarıda ve sunulan alternatif dışında herhangi bir ek istatistiki önyargı tanıtmak). Bu tür durumlar % 6, sayı üretecinin düşük sıralı bitlerde korelasyon düzlüklerine sahip olduğu durumlardır; örneğin rand, yüksek ve düşük bitleri "nihai güzelleşmek". Bir başka husus da 6'nın çok küçük olduğudur, cf. RAND_MAX, bu nedenle RAND_MAX6'nın katı değilse minimum etki olacaktır , ki bu muhtemelen değildir.

Sonuç olarak, bu günlerde, izlenebilirliği nedeniyle kullanıyorum % 6. Jeneratörün kendisi tarafından sunulanların ötesinde herhangi bir istatistiksel anormallik ortaya çıkarması muhtemel değildir. Hala şüpheniz varsa, kullanım durumunuz için uygun istatistiksel özelliklere sahip olup olmadığını görmek için jeneratörünüzü test edin.


12
% 6tarafından üretilen farklı değerlerin sayısı rand()6'nın katı olmadığı durumlarda yanlı bir sonuç üretir . Güvercin deliği ilkesi. Kabul edilirse, önyargı RAND_MAX6'dan çok daha büyük olduğunda küçüktür, ancak oradadır. Ve daha geniş hedef aralıkları için etki elbette daha büyüktür.
Pete Becker

2
@PeteBecker: Gerçekten, bunu netleştirmeliyim. Ancak, tamsayı bölme kesme etkileri nedeniyle, örnek aralığı RAND_MAX'a yaklaştıkça, güvercin deliklerine de sahip olduğunuzu unutmayın.
Bathsheba

2
@Bathsheba, bu kesme etkisi 6'dan büyük bir sonuca ve dolayısıyla tüm işlemin tekrar tekrar yürütülmesine yol açmaz mı?
Gerhardh

1
@Gerhardh: Doğru. Aslında, tam olarak sonuca götürür x==7. Genellikle, aralığı [0, RAND_MAX]7 alt aralığa , aynı boyutta 6 alt aralığa ve sonunda daha küçük bir alt aralığa bölersiniz . Son alt aralıktaki sonuçlar atılır. Bu şekilde sonunda iki daha küçük alt aralığa sahip olamayacağınız oldukça açık.
MSalters

@MSalters: Gerçekten. Ancak, diğer yolun kesilme nedeniyle hala acı çektiğini unutmayın. Benim hipotezim, istatistiksel tuzakların anlaşılması daha zor olduğu için halkın ikincisi için tombul olduğudur!
Bathsheba

13

Bu örnek kod std::rand, her gördüğünüzde kaşlarınızı kaldırması gereken eski bir kargo kültü balderdash vakası olduğunu göstermektedir .

Burada birkaç sorun var:

Sözleşme insanlar genellikle yoksul talihsiz ruhlar daha iyi bilmeyen bile-varsayalım ve hassas bunların içinde düşünmek olmaz terimler-olduğu randgelen numuneler homojen dağılımı 0 yılında tamsayılar üzerinde, 1, 2, ..., RAND_MAX, ve her çağrı bağımsız bir örnek verir .

İlk sorun, varsayılan sözleşmenin, her çağrıdaki bağımsız tek tip rastgele örneklemlerin aslında dokümantasyonun söylediği gibi olmamasıdır - ve pratikte, uygulamalar tarihsel olarak bağımsızlık için en yalın simülasyonu bile sağlamada başarısız olmuştur. Örneğin, C99 §7.20.2.1 ' randFonksiyon' detaylandırmadan şunu söyler:

randFonksiyonu, aralık 0 yalancı rasgele bir tamsayı dizisi hesaplar RAND_MAX.

Bu anlamsız bir cümle, çünkü sözde raslantısallık bir işlevin (veya işlevler ailesinin ) bir özelliğidir , bir tam sayı değildir, ancak bu, ISO bürokratlarının bile dili kötüye kullanmasını engellemez. Ne de olsa, bundan rahatsız olacak tek okuyucular rand, beyin hücrelerinin bozulmasından korktukları için belgeleri okumaktan daha iyisini biliyorlar .

C'deki tipik bir tarihsel uygulama şu şekilde çalışır:

static unsigned int seed = 1;

static void
srand(unsigned int s)
{
    seed = s;
}

static unsigned int
rand(void)
{
    seed = (seed*1103515245 + 12345) % ((unsigned long)RAND_MAX + 1);
    return (int)seed;
}

Bu, talihsiz bir özelliğe sahiptir; tek bir örnek, tek tip bir rastgele çekirdek altında tekdüze olarak dağıtılsa bile (özel değerine bağlıdır RAND_MAX), ardışık çağrılarda çift ve tek tamsayılar arasında değişir - sonra

int a = rand();
int b = rand();

ifade (a & 1) ^ (b & 1)% 100 olasılıkla 1 verir; bu, çift ​​ve tek tam sayılarda desteklenen herhangi bir dağılımdaki bağımsız rastgele örnekler için geçerli değildir . Böylelikle, 'daha iyi rastgeleliğin' yakalanması zor canavarını kovalamak için düşük dereceli bitleri atılması gereken bir kargo kültü ortaya çıktı. (Spoiler uyarısı: Bu teknik bir terim değildir. Bu, okuduğunuz her yerde nesrin ne hakkında konuştuğunu bilmediğini veya sizin fikriniz olmadığını ve küçümsendiğinizi düşündüğünün bir işaretidir .)

İkinci problem ise, her çağrı 0, 1, 2,…, üzerinde tek tip bir rastgele dağılımdan bağımsız olarak örnekleme yapsa bileRAND_MAX , sonucunun rand() % 6bir kalıp gibi 0, 1, 2, 3, 4, 5'e eşit olarak dağıtılmamasıdır. yuvarlama, RAND_MAX-1 modulo 6 ile uyumlu olmadığı sürece . Basit karşı örnek: Eğer RAND_MAX= 6 ise rand(), tüm sonuçların 1/7 olasılığa eşit olması, ancak başlangıçtaki rand() % 6sonuçların 2/7 olasılığı varken diğer tüm sonuçların 1/7 olasılığı .

Bunu yapmanın doğru yolu ret örnekleme ile geçerli: defalarca bağımsız tekdüze rasgele bir numune alın s0, 1, 2, ..., RAND_MAXve reddetmek sonuçları 0, 1, 2, ..., (örneğin) ((RAND_MAX + 1) % 6) - 1Eğer birini almak -eğer baştan başlayın; aksi takdirde verim s % 6.

unsigned int s;
while ((s = rand()) < ((unsigned long)RAND_MAX + 1) % 6)
    continue;
return s % 6;

Bu şekilde, rand()kabul ettiğimiz sonuçlar kümesi 6'ya eşit olarak bölünebilir ve her bir olası sonuç s % 6, aynı sayıda kabul edilen sonuç tarafından elde edilir rand(), bu nedenle rand()tek tip olarak dağıtılırsa öyle olur s. Deneme sayısında sınır yoktur , ancak beklenen sayı 2'den azdır ve başarı olasılığı deneme sayısıyla katlanarak artar.

Seçimi ait sonuçlarını siz cppreference.com kod bir yapar 6. Aşağıdaki her tam sayıya bunların eşit sayıda harita şartıyla önemsizdir reddetmek farklı bir şey hakkında garanti olduğunu yukarıda çünkü ilk sorunun, seçim çıktıların dağılımı veya bağımsızlığı ve pratikte düşük sıralı bitler 'yeterince rasgele görünmeyen' örüntüler sergiledi (bir sonraki çıktının bir öncekinin deterministik bir işlevi olduğunu unutmayın).rand()rand()

Okuyucu için alıştırma: cppreference.com'daki kodun, rand()0, 1, 2,…, üzerinde düzgün bir dağılım sağlaması halinde, kalıp silindirleri üzerinde düzgün bir dağılım sağladığını kanıtlayın RAND_MAX.

Okuyucu için alıştırma: Neden bir veya diğer alt kümelerin reddetmesini tercih edebilirsiniz? İki durumda her bir deneme için hangi hesaplama gereklidir?

Üçüncü bir problem, tohum boşluğunun o kadar küçük olmasıdır ki, tohum tekdüze olarak dağıtılmış olsa bile, programınız ve bir sonuç hakkında bilgi sahibi olan bir düşman, tohumu ve sonraki sonuçları kolayca tahmin edemez, bu da onları öyle görünmüyor. sonuçta rastgele. Bu yüzden bunu kriptografi için kullanmayı düşünme bile.

Süslü aşırı mühendislik rotasına ve C ++ 11'lere gidebilirsiniz std::uniform_int_distribution sınıfına uygun bir rastgele cihazla ve her zaman popüler olan Mersenne twister gibi en sevdiğiniz rastgele motorlastd::mt19937 dört yaşındaki kuzeninizle zar atabilirsiniz, ancak bu bile gitmeyecek kriptografik anahtar materyali oluşturmaya uygun olun - ve Mersenne twister, müstehcen bir kurulum süresiyle CPU'nuzun önbelleğine zarar veren çok kilobaytlık bir durumla korkunç bir uzay domuzudur, bu nedenle, örneğin , paralel Monte Carlo simülasyonları için bile kötüdür. tekrarlanabilir alt hesaplama ağaçları; popülaritesi büyük olasılıkla akılda kalıcı adından kaynaklanmaktadır. Ancak bu örnekte olduğu gibi oyuncak zar atmak için kullanabilirsiniz!

Diğer bir yaklaşım, basit bir hızlı anahtar silme PRNG'si gibi küçük bir duruma sahip basit bir şifreleme sözde rasgele sayı üreteci veya kendinize güveniyorsanız sadece AES-CTR veya ChaCha20 gibi bir akış şifresi kullanmaktır ( örneğin , bir Monte Carlo simülasyonunda doğa bilimlerinde araştırma), devletin tehlikeye atılması durumunda geçmiş sonuçları tahmin etmenin olumsuz sonuçlarının olmadığı.


4
"müstehcen bir kurulum süresi" Her halükarda gerçekten birden fazla rastgele sayı üreteci (iş parçacığı başına) kullanmamalısınız, bu nedenle programınız çok uzun çalışmadığı sürece kurulum süresi amortismana tabi tutulacaktır.
JAB

2
BTW'ye sorudaki döngünün tamamen aynı (RAND_MAX + 1 )% 6değerlerle aynı ret örneklemesini yaptığını anlamadığı için olumsuz oy verin . Olası sonuçları nasıl alt bölümlere ayırdığınız önemli değil . [0, RAND_MAX)Kabul edilen aralığın boyutu 6'nın katı olduğu sürece, bunları aralığın herhangi bir yerinden reddedebilirsiniz . Cehennem, herhangi bir sonucu reddedebilirsiniz x>6ve %6artık ihtiyacınız olmayacak.
MSalters

12
Bu cevaptan pek memnun değilim. Rants iyi olabilir ama sen yanlış yöne gidiyorsun. Örneğin, "daha iyi rastgeleliğin" teknik bir terim olmadığından ve anlamsız olduğundan şikayet ediyorsunuz. Bu yarı doğrudur. Evet, teknik bir terim değil, ancak bağlam içinde mükemmel bir şekilde anlamlı bir kısaltmadır. Böyle bir terimi kullananların cahil veya kötü niyetli olduklarını ima etmek, başlı başına bunlardan biridir. “İyi rastgeleliği” kesin olarak tanımlamak çok zor olabilir, ancak bir işlev daha iyi veya daha kötü rastgelelik özelliklerine sahip sonuçlar ürettiğinde anlamak yeterince kolaydır.
Konrad Rudolph

3
Bu cevabı beğendim. Biraz rant, ama pek çok iyi arka plan bilgisi var. Unutmayın, GERÇEK uzmanlar her zaman yalnızca donanımsal rastgele üreteçleri kullanır, sorun bu kadar zordur.
Tiger4Hire

10
Benim için tam tersi. İyi bilgiler içermesine rağmen, fikirden başka bir şey olarak karşımıza çıkmayacak kadar ranttır. Yararlılık bir yana.
Bay Lister

2

Hiçbir şekilde deneyimli bir C ++ kullanıcısı değilim, ancak std::rand()/((RAND_MAX + 1u)/6)daha az önyargılı olmakla ilgili diğer yanıtların 1+std::rand()%6gerçekte olduğundan daha az önyargılı olup olmadığını görmekle ilgileniyordum . Bu yüzden, her iki yöntemin sonuçlarını tablo haline getirmek için bir test programı yazdım (C ++ 'ı yıllarca yazmadım, lütfen kontrol edin). Kodu çalıştırmak için bir bağlantı burada bulunur . Ayrıca aşağıdaki gibi yeniden üretilir:

// Example program
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <string>

int main()
{
    std::srand(std::time(nullptr)); // use current time as seed for random generator

    // Roll the die 6000000 times using the supposedly unbiased method and keep track of the results

    int results[6] = {0,0,0,0,0,0};

    // roll a 6-sided die 20 times
    for (int n=0; n != 6000000; ++n) {
        int x = 7;
        while(x > 6) 
            x = 1 + std::rand()/((RAND_MAX + 1u)/6);  // Note: 1+rand()%6 is biased

        results[x-1]++;
    }

    for (int n=0; n !=6; n++) {
        std::cout << results[n] << ' ';
    }

    std::cout << "\n";


    // Roll the die 6000000 times using the supposedly biased method and keep track of the results

    int results_bias[6] = {0,0,0,0,0,0};

    // roll a 6-sided die 20 times
    for (int n=0; n != 6000000; ++n) {
        int x = 7;
        while(x > 6) 
            x = 1 + std::rand()%6;

        results_bias[x-1]++;
    }

    for (int n=0; n !=6; n++) {
        std::cout << results_bias[n] << ' ';
    }
}

Daha sonra bunun çıktısını aldım chisq.testve sonuçların beklenenden önemli ölçüde farklı olup olmadığını görmek için bir Ki-kare testi yapmak için R'deki fonksiyonu kullandım . Bu yığın değiş tokuş sorusu, kalıp adaletini test etmek için ki-kare testini kullanma hakkında daha fazla ayrıntıya giriyor: Bir kalıbın adil olup olmadığını nasıl test edebilirim? . İşte birkaç çalıştırmanın sonuçları:

> ?chisq.test
> unbias <- c(100150, 99658, 100319, 99342, 100418, 100113)
> bias <- c(100049, 100040, 100091, 99966, 100188, 99666 )

> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 8.6168, df = 5, p-value = 0.1254

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 1.6034, df = 5, p-value = 0.9008

> unbias <- c(998630, 1001188, 998932, 1001048, 1000968, 999234 )
> bias <- c(1000071, 1000910, 999078, 1000080, 998786, 1001075   )
> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 7.051, df = 5, p-value = 0.2169

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 4.319, df = 5, p-value = 0.5045

> unbias <- c(998630, 999010, 1000736, 999142, 1000631, 1001851)
> bias <- c(999803, 998651, 1000639, 1000735, 1000064,1000108)
> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 7.9592, df = 5, p-value = 0.1585

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 2.8229, df = 5, p-value = 0.7273

Yaptığım üç çalışmada, her iki yöntem için p değeri, önemi test etmek için kullanılan tipik alfa değerlerinden her zaman daha büyüktü (0.05). Bu, ikisinin de önyargılı olduğunu düşünmeyeceğimiz anlamına gelir. İlginç bir şekilde, sözde tarafsız yöntemin sürekli olarak daha düşük p değerlerine sahip olması, aslında daha önyargılı olabileceğini gösterir. Uyarı, sadece 3 koşu yaptığım.

GÜNCELLEME: Cevabımı yazarken, Konrad Rudolph aynı yaklaşımı benimseyen ancak çok farklı bir sonuç alan bir cevap gönderdi. Cevabına yorum yapacak itibarım yok, bu yüzden burada ele alacağım. İlk olarak, asıl önemli olan, kullandığı kodun, her çalıştırıldığında rastgele sayı üreteci için aynı tohumu kullanmasıdır. Tohumu değiştirirseniz, aslında çeşitli sonuçlar elde edersiniz. İkincisi, tohumu değiştirmezseniz, ancak denemelerin sayısını değiştirirseniz, çeşitli sonuçlar da alırsınız. Ne demek istediğimi görmek için, bir büyüklük sırasına göre artırmayı veya azaltmayı deneyin. Üçüncüsü, beklenen değerlerin tam olarak doğru olmadığı bazı tamsayı kesmeleri veya yuvarlamaları vardır. Muhtemelen bir fark yaratmak için yeterli değil, ama orada.

Temel olarak, özetle, yanlış bir sonuç alabileceği doğru tohumu ve deneme sayısını elde etti.


Sizin uygulaması nedeniyle sizin açınızdan anlaşmazlıktan ölümcül bir kusuru içerir: aktarılan bölüm edilir değil karşılaştırarak rand()%6ile rand()/(1+RAND_MAX)/6. Daha ziyade, geri kalanın doğrudan alınması ile reddedilme örneklemini karşılaştırmaktadır (bir açıklama için diğer cevaplara bakınız). Sonuç olarak, ikinci kodunuz yanlıştır ( whiledöngü hiçbir şey yapmaz). İstatistiksel testlerinizin de sorunları vardır (sağlamlık için testinizin tekrarlarını çalıştıramazsınız, düzeltme yapmadınız,…).
Konrad Rudolph

1
@KonradRudolph Cevabınıza yorum yapacak bir temsilcim yok, bu yüzden onu benimkine bir güncelleme olarak ekledim. Ayrıca, yanlış sonuç veren her seferinde ayarlanmış bir tohum ve deneme sayısı kullanmak gibi ölümcül bir kusur var. Farklı tohumlarla tekrarlar çalıştırdıysanız, bunu yakalamış olabilirsiniz. Ama evet, doğru, while döngüsü hiçbir şey yapmaz, ancak bu belirli kod bloğunun sonuçlarını da değiştirmez
anjama

Aslında tekrarlar yaptım. Standartlara uygun bir şekilde rastgele bir tohum oluşturmak std::srand(ve kullanmamak <random>) oldukça zor olduğundan ve karmaşıklığının kalan koddan uzaklaşmasını istemedim. Bu aynı zamanda hesaplama için de önemsizdir: bir simülasyonda aynı sırayı tekrarlamak tamamen kabul edilebilir. Tabii ki, farklı tohumlar edecek farklı sonuçlar ve bazı sivil anlamlı olacaktır. Bu, p değerinin nasıl tanımlandığına bağlı olarak tamamen beklenen bir durumdur.
Konrad Rudolph

1
Sıçanlar, tekrarlarımda bir hata yaptım; ve haklısınız, tekrarlı çalışmaların 95. kuantülü p = 0.05'e oldukça yakın - yani tam olarak altında beklediğimiz şey o zaman boş. Özetle, benim standart kütüphane uygulamam std::rand, rastgele tohumlar aralığında bir d6 için oldukça iyi yazı tura simülasyonları sağlıyor.
Konrad Rudolph

1
İstatistiksel önem , hikayenin yalnızca bir kısmıdır. Boş bir hipoteziniz (tekdüze dağıtılmış) ve alternatif bir hipoteziniz (modülo sapması) var - aslında, modulo önyargısının etki boyutunuRAND_MAX belirleyen, seçimine göre indekslenmiş bir alternatif hipotezler ailesi . İstatistiksel anlamlılık, boş hipotez altında yanlış bir şekilde reddetme olasılığınızdır. İstatistiksel güç nedir - alternatif bir hipotez altında testinizin sıfır hipotezini doğru bir şekilde reddetme olasılığı ? RAND_MAX = 2 ^ 31 - 1 olduğunda bu yolu tespit eder miydiniz ? rand() % 6
Squeamish Ossifrage

2

Rastgele bir sayı üreteci, ikili rakamların akışı üzerinde çalışıyormuş gibi düşünülebilir. Jeneratör, akışı parçalara ayırarak sayılara dönüştürür. Eğer std:randfonksiyon a ile çalışıyorRAND_MAX bu durumda, her dilim 15 bit kullanarak, 32767 arasında.

Kişi, 0 ile 32767 arasında bir sayıdaki modülleri aldığında, 5462 '0'lar ve' 1'ler, ancak sadece 5461 '2'ler,' 3'ler, '4'ler ve' 5'ler bulunur. Dolayısıyla sonuç önyargılıdır. RAND_MAX değeri ne kadar büyükse, o kadar az önyargı olacaktır, ancak bu kaçınılmazdır.

Önyargılı olmayan, [0 .. (2 ^ n) -1] aralığındaki bir sayıdır. 3 biti çıkararak, 0..7 aralığında bir tam sayıya dönüştürerek ve 6 ile 7'yi reddederek 0..5 aralığında (teorik olarak) daha iyi bir sayı üretebilirsiniz.

Bit akışındaki her bitin, akışta nerede olduğuna veya diğer bitlerin değerlerine bakılmaksızın "0" veya "1" olma şansının eşit olması umulmaktadır. Pratikte bu son derece zordur. Yazılım PRNG'lerinin birçok farklı uygulaması hız ve kalite arasında farklı ödünler sunar. std::randEn düşük kalite için en hızlı hızı sunan gibi doğrusal bir uyumlu jeneratör . Kriptografik bir jeneratör, en düşük hız için en yüksek kaliteyi sunar.

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.