【问题标题】:Why is rand() % N sufficient for small distributions?为什么 rand() % N 对于小型分布来说足够了?
【发布时间】:2021-12-03 21:38:42
【问题描述】:

我经常听说,如果你想要一个均匀分布,你永远不应该修改你的随机数生成器的结果。但是,我发现使用 std::uniform_int_distribution 对非常小的范围没有任何影响。

以下是使用 mod 和 uniform_int_distribution 值 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";
}

结果:

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

我猜它与 2 个字节有关?我只是想知道这在数学上是如何有效的,因为它逐步通过随机数生成器和修改结果。如果范围足够小,这是否意味着 mod 会创建均匀分布?为什么是 2 字节范围而不是更多?

【问题讨论】:

  • 通常情况下,至少我还没有看到不是这样的实现,[0, RAND_MAX] 的域是2 的倍数。 16 也是2 的倍数,因此用它修改rand 的结果应该保持分布。尝试使用非 2 的倍数,看看是否会得到不同的结果。
  • 您的测试不足以评价均匀分布。尝试数十亿个样本。
  • 这里的第一个问题是“我经常听到”。从谁?在哪里?需要引用!另外,你用这些数字做什么?如果您需要它们进行密码学,那么好吧,其他假设适用。
  • @NathanOliver 更像是“尝试使用 2 的非 multiple 幂”

标签: c++ random distribution mersenne-twister uniform-distribution


【解决方案1】:

当随机位源返回的唯一值的数量不是除数的倍数时,使用模运算符会经常在返回的结果中引入偏差。

举个简单的例子,如果你的随机源返回 4 位 (0-15),并且你想要 0-2 范围内的值,使用 gen() % N 你会得到 6 0s, 5 1s , 和 5 2s。这会使您的结果偏低。

使用乘法除法 (gen() * N / RANGE) 仍然会在返回的每个结果的特定数量上留下不平衡,但这种不平衡会在结果中均匀分布,从而减少或消除低偏差。它还必须应对乘法中的溢出。在前面的示例中,您将获得 5 个0s、6 个1s 和 5 个0s。

第三种选择是检查返回的位以查看该值是否在最高结果中(这将导致偏差),如果是这种情况,则重新生成随机位。这在代码中引入了条件,生成随机数的时间是开放式的(而不是固定的)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-27
    • 2017-04-13
    • 1970-01-01
    • 2012-06-20
    • 1970-01-01
    相关资源
    最近更新 更多