Random Number Generator etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Random Number Generator etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

17 Ocak 2019 Perşembe

std::random_device Sınıfı - Yaratması Maliyetlidir

Giriş
Şu satırı dahil ederiz.
#include<random>
Açıklaması şöyle
std::random_device may be expensive to create. It may open a device feeding it data, and that takes some time. It can also be expensive to call because it requires entropy to deliver a truly random number, not a pseudo random number.
Donanım tabanlıdır. Eski bilgisayarlarda donanım tabanlı dağılım için ne yapıldığını anlatan bir yazı şöyle.

Eğer donanım desteği yoksa algoritma tabanlı bir üretece dönüşür. Uyarı vermeden yapılan bu geçiş istenmeyen sonuçlara sebep olabilir. Açıklaması şöyle.
std::random_device, introduced in C++11, is not recommended because its specification leaves considerably much to be desired. For example, std::random_device can fall back to a pseudorandom number generator of unspecified quality without much warning.

Constructor
Şöyle yaparız.
std::random_device rd;
entropy metodu
entropy şu anlama gelir.
entropy is the measure of surprise
Windows'ta bu metod hep 32 döner.

Linux'ta işletim sisteminin entropisini görmek için şöyle yaparız.
cat /proc/sys/kernel/random/entropy_avail
Eğer donanım tabanlı bir üreteç yoksa yine yazılım tabanlı bir üreteç kullanılır. Açıklaması şöyle.
std::random_device may be implemented in terms of an implementation-defined pseudo-random number engine if a non-deterministic source (e.g. a hardware device) is not available to the implementation. In this case each std::random_device object may generate the same number sequence.
Bu durumda sınıfın entropy metodu 0 döner. Şöyle yaparız.
std::random_device rd;
std::cout << rd.entropy();
Çıktı olarak şunu alırız.
0
Diğer Üreteçleri İlklendirme - mt19937
Şöyle yaparız.
std::random_device rd;
std::mt19937 eng(rd());
Bu kod eleştirilere maruz kalıyor. Sebepleri şöyle. Tüm bunlar şu anlama geliyor mt19937'yi ilklendirmek için random_device yeterli değil.
1. rd() returns a single unsigned int. This has at least 16 bits and probably 32. That's not enough to seed MT's 19937 bits of state.

2. Using std::mt19937 gen(rd());gen() (seeding with 32 bits and looking at the first output) doesn't give a good output distribution. 7 and 13 can never be the first output. Two seeds produce 0. Twelve seeds produce 1226181350.

3. std::random_device can be, and sometimes is, implemented as a simple PRNG with a fixed seed. It might therefore produce the same sequence on every run. (Link) This is even worse than time(NULL).



4 Eylül 2017 Pazartesi

C++ ile Random Number Generator

C++11 ile eskiden sadece boost'un sağladığı birçok sınıf geliyor. Rastgele sayılar ile çalışırken çakışmalara hazırlıklı olmak gerekir.

Üreteç sınıfları - Generators

Generator sınıflarının amacı sayı üretmektir. İki çeşit üreteç var. Bunlar true random generator ve pseudo random number generator olarak sınıflandırılıyorlar.

true random number generator sınıflar donanım tabanlı ve yavaşlar. pseudo olanlar ise yazılım tabanlı ve hızlılar ancak daha kötü dağılım sağlıyorlar. Aşağıdaki şekillerde fark görülebilir.

True Random Number - Donanım Tabanlı


Pseudo Random Number - Yazılım Tabanlı

True Random Generator 
std::random_device yazısına taşıdım.

Pseudo Generator Sınıfları
Bu sınıfların isimleri _engine kelimesi ile biter.

İlklendirme
Pseudo random engine sınıflarını ilklendirmek için üç yöntem var. İlki true random generator kullanmak. Bu bence iyi bir fikir.
std::random_device rd;
std::mt19937 gen(rd());
İkincisi ise saati kullanmak. Ben bu fikri pek sevmiyorum. Bir başka örnek burada.
#include <random>
#include <chrono>

auto seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
C kodu kullanarak ilklendirmek için şöyle yaparız.
std::mt19937 generator(clock());
Üçüncüsü ise ilklendirmemek. Bu durumda default bir seed ile ilklenir. Bu zaten en kötü fikir.

1. default_random_engine
std::default_random_engine yazısına taşıdım.

2. mersenne_twister_engine 

1. mt19937
std::mt19937 yazısına taşıdım.

3. linear_congruential_engine
Bu sınıfın özelleşmiş hallerinden bir tanesi min_std_rand0. Bu sınıf şöyle tanımlı
linear_congruential_engine<uint_fast32_t, 16807, 0, 2147483647> minstd_rand0;
Sabitler sırasıyla a,c,m olarak anılıyor. Kullanılan formül şöyle
(a*x+c)%m

Sabitlerin base 8 olması gerektiği söyleniyor ancak ne kast edildiğini anlamadım

Dağılım Sınıfları - Distributions
Dağılım sınıflarının amacı üreteçlerin verdiği sayıları belli bir örüntüye göre (Uniform, Normal, Binomial) dağıtmaktır. Her dağılım sınıfı constructor metodu bir engine ile beraber çalışır.

  • Uniform Distribution - Tek Düze Dağılım demektir. 
  • Normal Distribution - Çan eğrisi dağılım demektir. Gaussian olarak ta bilinir. 
  • Bernoulli - Binomial Distribution - Binom dağılım demektir. 
  • Rate based Distribution 
  • Piecewise Distribution 
  • Canonical Number
gibi sınıflar var.

Nasıl Kullanırız


Dağılım sınıflarının constructor metodlarına aralık girilir. Daha sonra distribution sınıflarının () metodu verilen üreteci kullanarak sayı döndürür.

normal_distribution
normal_distribution Sınıfı yazısına taşıdım

uniform_int_distribution
uniform_int_distribution Sınıfı sınıfı yazısına taşıdım.

uniform_real_distribution
uniform_real_distribution Sınıfı yazısına taşıdım.

discrete_disctribution
discrete_disctribution Sınıfı yazısına taşıdım.

Engine Adapters
  • Discard Block Engine 
  • Independent Bits Engine 
  • Shuffle Order Engine
gibi sınıflar var.

29 Nisan 2016 Cuma

std::default_random_engine - Bir Pseudo-random number generator (PRNG)

Giriş
Şu satırı dahil ederiz.
#include<random>
C++ kütüphanesinin gerçekleştirimine bırakılmış. Açıklaması şöyle
Remark: The choice of engine type named by this typedef is implementation-defined. [ Note: The implementation may select this type on the basis of performance, size, quality, or any combination of such factors, so as to provide at least acceptable engine behavior for relatively casual, inexpert, and/or lightweight use. Because different implementations may select different underlying engine types, code that uses this typedef need not generate identical sequences across implementations. — end note ]
Bence bu sınıfı kullanmamak gerekir. Bu sınıf GCC'de minstd_rand0 olarak gerçekleştirilmiş.
VS2012'de ise mt19937 olarak gerçekleştirilmiş .

constructor - default
Sınıfı şöyle yaratabiliriz. Ancak bu durumda seed vermediğimiz için hep aynı sonuçları elde ederiz.
std::default_random_engine generator;
constructor - time
Sistem saatini kullanarak şöyle yaparız.
std::default_random_engine generator( (unsigned int)time(0) );
constructor - chrono time
Chrono kullanarak şöyle yaparız.
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator (seed));
constructor - random_device
Donanım tabanlı bir üreteci kullanarak şöyle yaparız.
std::default_random_engine generator( std::random_device{}() );