对于rand_m 生成1到n的问题

本文深入探讨了如何利用已有的rand7()函数,通过数学公式与逻辑处理,构建出能够随机产生1到10之间整数的rand10()函数。详细解释了生成等概率数集的原理,并提供了三种实现方法,包括等概率生成1到49的通用策略,以及针对特定范围的优化技巧。文章旨在为编程爱好者提供一种有趣且实用的随机数生成解决方案。

今天在网上看到了在网上传的面试题,题目是:

已知有个rand7()的函数,它可以返回1到7之间的随机自然数,现在请让利用这个rand7()来构造rand10()使它能 随机地产生1~10之间的自然数。

参考以下网址,我觉得写的不错。好像这是道编程之美上的题?

http://www.towork.me/questions/451/

 

对于这一类题目的一般公式是: m*(rand_m()-1)+rand_m();n<m && n<=m*m

注: rand_m() 可以生成 [1,m]的自然数, 要生成 rand_n() 即[1,n]的自然数的公式。

其实,这个问题,其实就是,我先生成等间距的一段数(间距一定是m),这个数分别为 0, m, 2m, 3m,..., (m-1)*m, m*m。 在 rand_m()中进行-1, 就是能够产生0。注意这个间距相当于是等概率产生的,那么,我在先定了一个起点,在这个起点的基础上,再加上一个数值,就可以了。(所以,这个地方就要求,间距必须是m, 这样通过rand_m 才能覆盖两个间距的所有的数,同时对于生成的起点,也是只有一种可能)

 

就如同,本题目,按照这个公式,我们就可以等概率地生成1~49间的所有数了。(7*6+7, 最大范围),那如何生成1--10呢。其实,等概率地生成1~49, 就可以等概率地生成1~10,我们最简单的方法,可以直接判断这个结果是否在1~10之间就可以,如果不在,就重新再试一次。但是这样速度可能比较慢。所以我们可以在1~m*m 中,挑选几组 1~10,也就是可以是 1~10,11~20, 。。。,这样就可以更快地得到我们的结果。

所以我觉得下面这个程序写的不错,就是上面链接中的程序。

 

int random_n()

{

int val = 0 ;

int t; // t为n最大倍数,且满足 t <= m * m

do {

    val = m * (random_m() - 1) + random_m();

} while (val > t);

return val;
}

 可以略微对val处理一下。

 

2012-03-01

 方法2:

例如Rand7会生成1,2,3,4,5,6,7这些数。我们以4为分界点。

如果生成1-3这3个数字时,我们在Rand7,只取1-5这几个数字。

如果生成5-7这3个数字时,我们在Rand7+3,只取5-10这几个数字。

 

 

方法3:

例如Rand7会生成1,2,3,4,5,6,7这些数。我们以4为分界点。

由于 rand7 是 1..7

rand7+3是 4..10, 直接返回结果时,4..7 的概率会多一倍

全局标志位 flag = 0; 记录每当出现再次4..7时才进行输出

1.如果生成1-3这3个数字时,我们在Rand7

 1.1如果生成1-3,直接输出

 1.2如果生成4-7,如果flag=0, 则置flag = 1, 再调用一次Rand10.

                          flag = 1, 直接返回此值, flag = 0

 

2.如果生成5-7这3个数字时,我们在Rand7+3,只取5-10这几个数字。

 同理

 

<think> 我们正在讨论MATLAB中的随机数生成函数,特别是`rand(RandStream, m, n)`的使用方法。根据引用[2],我们知道`rand`函数的基本语法包括使用随机种子(RandStream)作为第一个参数,然后是矩阵维度m和n。该函数用于生成均匀分布在(0,1)之间的伪随机数。 具体到`rand(RandStream, m, n)`: - 第一个参数`RandStream`是一个随机数流对象,用于控制随机数的生成。通过设置不同的随机数流,我们可以实现可重复的随机数生成或者创建独立的随机数序列。 - 参数`m`和`n`分别指定生成随机数矩阵的行数和列数。 功能:生成一个大小为m×n的均匀分布伪随机数矩阵,该矩阵中的每个元素都在(0,1)区间内。并且,这个随机数序列是由传入的RandStream对象决定的。 使用方法: 1. 首先,我们可以创建一个随机数流对象。在MATLAB中,可以使用`RandStream`类来创建。例如,创建一个使用'mt19937ar'算法(即Mersenne Twister算法)的随机数流: stream = RandStream('mt19937ar', 'Seed', 0); 2. 然后,我们可以使用这个流对象来生成随机数: rand_num = rand(stream, m, n); 这样,通过设置相同的随机数流(相同的算法和种子),我们就可以在每次运行时得到相同的随机数序列。 举例: 如果我们想要生成一个2行3列的随机数矩阵,并且希望每次运行程序时得到相同的结果(可重复性),可以这样做: stream = RandStream('mt19937ar', 'Seed', 0); % 设置随机数流,种子为0 A = rand(stream, 2, 3); 这样,每次运行这两行代码,得到的矩阵A都是相同的。 注意: - 使用随机数流对象可以让我们更灵活地控制随机数的生成,比如我们可以创建多个独立的随机数流,或者重置一个随机数流的状态。 - 在MATLAB中,全局随机数流(即默认的随机数流)可以通过`RandStream.getGlobalStream`获得,设置全局随机数流可以使用`RandStream.setGlobalStream`。 另外,除了使用种子(Seed)初始化随机数流,我们还可以使用其他属性,例如'NormalTransform'(用于正态分布随机数的生成方法)等。但针对均匀分布rand函数,主要关注种子和算法即可。 总结:`rand(RandStream, m, n)`允许我们通过指定随机数流来生成可重复的随机数序列,这在需要复现实验结果时非常有用。 </think> ### `rand(RandStream, m, n)` 函数详解 #### 一、核心功能 在 MATLAB 中,`rand(RandStream, m, n)` 用于**生成可控的均匀分布伪随机数矩阵**(区间 $(0,1)$),其随机性由指定的随机数流对象(`RandStream`)控制。与默认的 `rand(m, n)` 相比,它支持: 1. **精准控制随机种子**:避免全局随机状态干扰实验结果[^2] 2. **独立随机序列**:创建并行计算中互不干扰的随机流 3. **结果重现性**:固定种子时,每次生成相同的随机数序列 #### 二、参数说明 | 参数 | 数据类型 | 作用 | |-------------|-------------|----------------------------------------------------------------------| | `RandStream`| 随机流对象 | 控制随机数生成算法和初始状态(如 `mt19937ar`, `dsfmt19937` 等算法) | | `m` | 正整数 | 输出矩阵的行数 | | `n` | 正整数 | 输出矩阵的列数 | #### 三、使用步骤 ```matlab % 1. 创建随机流对象 (例如使用 Mersenne Twister 算法,种子=42) stream = RandStream('mt19937ar', 'Seed', 42); % 2. 生成 3x2 随机矩阵 randomMatrix = rand(stream, 3, 2); ``` **输出示例**(种子固定时结果恒定): ``` 0.3745 0.1690 0.9507 0.6491 0.7320 0.7317 ``` #### 四、关键应用场景 1. **可复现实验** ```matlab stream = RandStream('dsfmt19937', 'Seed', 100); % 固定种子 data = rand(stream, 1e6, 1); % 百万级可复现随机数据 ``` 2. **并行计算隔离** ```matlab parfor i = 1:4 localStream = RandStream('Threefry', 'Seed', i); % 各进程独立种子 localData = rand(localStream, 1000, 1); end ``` 3. **算法对比测试** ```matlab stream1 = RandStream('mt19937ar', 'Seed', 1); stream2 = RandStream('simdTwister', 'Seed', 1); A = rand(stream1, 5, 5); % 相同种子不同算法 B = rand(stream2, 5, 5); ``` #### 五、注意事项 1. **全局流隔离**:通过 `RandStream` 对象生成的随机数**不影响**全局随机状态(`rng` 命令控制的默认流)[^2] 2. **算法选择**:使用 `RandStream.list` 查看支持的算法(如高效并行的 `Threefry`) 3. **重置状态**:需重置流状态时调用 `reset(stream)` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值