随机生成[0,n)(n<=RAND_MAX)的数

本文介绍了一个简单的随机数生成算法,该算法确保了生成的随机数在指定范围内均匀分布。通过循环调用rand()函数直到得到满足条件的随机数,再对其进行取模运算,最终返回所需的随机数。
int rand_n(int n)
{
    assert(n>=0 && n<=RAND_MAX);

    int k=rand();
    int M=RAND_MAX/n*n;
    while (k>=M)
    {
        k=rand();
    }

    return k%n;
}

### 代码问题分析 #### 1. 随机数种子问题 `srand(time(0));` 用于设置随机数种子。使用 `time(0)` 作为种子,它返回当前时间的秒。这意味着如果程序在同一秒内多次运行,会得到相同的随机数序列,因为种子没有变化;而且在多线程环境中,多个线程同时调用 `srand(time(0))` 可能会导致不同线程得到相同的随机数序列,因为同一时刻时间是相同的 [^2]。 #### 2. 按位与操作问题 - `rand_a = rand() & 5;`:`&` 是按位与运算符,这里将 `rand()` 生成随机数与 `5`(二进制 `101`)进行按位与操作。这会限制随机数的取值范围,最终 `rand_a` 只能是 `0`、`1`、`4`、`5` 这几个值,而不是在一个连续的区间内随机取值,失去了随机数的均匀性。 - `rand_b = rand() & 10000;`:同理,将 `rand()` 生成随机数与 `10000`(二进制 `10011100010000`)进行按位与操作,会使 `rand_b` 的取值局限于某些特定的值,不是在一个连续区间内均匀随机。 - `rand_c = rand() & 60 - 30;`:这里先计算 `60 - 30 = 30`(二进制 `11110`),然后将 `rand()` 生成随机数与 `30` 进行按位与操作,同样会使 `rand_c` 的取值局限,不是均匀随机的。 #### 3. 运算符优先级问题 `rand_c = rand() & 60 - 30;` 中,由于 `-` 运算符优先级高于 `&` 运算符,实际计算顺序是 `rand() & (60 - 30)`,可能不是代码作者的本意。 #### 4. 范围问题 在某些平台下(如 Windows),`RAND_MAX` 只有 `32768`。如果需要的范围大于 `32768`,仅使用 `rand()` 可能无法满足需求 [^3]。 ### 优化建议 #### 1. 随机数种子 可以考虑使用更安全的随机数种子生成方式,例如使用 `<random>` 库中的随机数引擎和分布,或者在多线程环境中为每个线程设置不同的种子。 #### 2. 随机数范围生成 使用 `%` 运算符或 `<random>` 库来生成指定范围的随机数,以保证随机数的均匀性。 #### 3. 代码示例 ```cpp #include <iostream> #include <random> #include <chrono> int main() { // 使用 <random> 库生成随机数 std::random_device rd; std::mt19937 gen(rd()); // 定义随机数范围 std::uniform_int_distribution<> dis_a(0, 5); std::uniform_int_distribution<> dis_b(0, 10000); std::uniform_int_distribution<> dis_c(30, 60); // 生成随机数 int rand_a = dis_a(gen); int rand_b = dis_b(gen); int rand_c = dis_c(gen); // 输出随机数 std::cout << rand_a << std::endl; std::cout << rand_b << std::endl; std::cout << rand_c << std::endl; return 0; } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值