vendredi 15 octobre 2021

Why is rand() % N sufficient for small distributions?

I've often heard that you should never mod the result of your random number generator if you want a uniform distribution. However, I've seen that using a std::uniform_int_distribution makes no difference for significantly small ranges.

Below is an example using both mod and uniform_int_distribution for values 0 - 15:

std::mt19937 gen;
gen.seed(0);

int ROWS = 6;
int COLS = 10;

std::cout << "mod: \n";
for (size_t i = 0; i < ROWS; ++i){
    for (size_t j = 0; j < COLS; ++j){
        std::cout << std::setw(2) << gen() % 16 << " ";
    }
    std::cout << "\n";
}
std::cout << "\n";

gen.seed(0);
std::uniform_int_distribution<> distrib(0, 15);

std::cout << "dist: \n";
for (size_t i = 0; i < ROWS; ++i){
    for (size_t j = 0; j < COLS; ++j){
        std::cout << std::setw(2) << distrib(gen) << " ";
    }
    std::cout << "\n";
}

results:

mod: 
12 15  5  0  3 11  3  7  9  3 
 5  2  4  7  6  8  8 12 10  1 
 6  7  7 14  8  1  5  9 13  8 
 9  4  3  0  3  5 14 15 15  0 
 2  3  8  1  3 13  3  3 14  7 
 0  1  9  9 15  0 15 10  4  7

dist: 
12 15  5  0  3 11  3  7  9  3 
 5  2  4  7  6  8  8 12 10  1 
 6  7  7 14  8  1  5  9 13  8 
 9  4  3  0  3  5 14 15 15  0 
 2  3  8  1  3 13  3  3 14  7 
 0  1  9  9 15  0 15 10  4  7

I guess it has something to do with 2 bytes? I'm just wondering how this is valid mathematically since its stepping through the random number generator and modding results. Does this mean mod creates a uniform distribution if the range is small enough? And why a 2 byte range and not more?




Aucun commentaire:

Enregistrer un commentaire