生成范围内的随机数? [复制]
Posted
技术标签:
【中文标题】生成范围内的随机数? [复制]【英文标题】:Generate a random number within range? [duplicate] 【发布时间】:2011-03-01 06:08:10 【问题描述】:可能重复:Generating Random Numbers in Objective-C
如何生成一个范围内的随机数?
【问题讨论】:
重复 - f.e. ***.com/questions/160890/… 您是否尝试过搜索?这已经被问了好六次了。此外,以下所有答案都是错误的,因为rand
不是一个好的 RNG,需要播种。你应该改用arc4random
。
@Dave:不能保证rand()
一定是坏的,只是不能保证它是好的。在不知道预期目的的情况下推荐 arc4random 几乎没有意义(如果有的话)。无论如何,大多数初学者都不会做任何真正重要的生成器质量的事情。
@Jerry 同意了。但是,初学者可能根本不知道他需要播种,这是 arc4random 的好处之一。关于这个话题有很多讨论:google.com/search?q=site:***.com+arc4random+rand
完全重复:***.com/questions/2509679/…
【参考方案1】:
int rand_range(int min_n, int max_n)
return rand() % (max_n - min_n + 1) + min_n;
对于分数:
double rand_range(double min_n, double max_n)
return (double)rand()/RAND_MAX * (max_n - min_n) + min_n;
【讨论】:
这不会给出均匀分布(除了二次幂)。 我知道,但它工作得很快,而且对于小范围的分布是可以的。这对游戏编码很有好处。无论如何,我应该把这个写在答案的某个地方。 @Oli 谁在乎?请参阅上面答案中 Ukko 的评论。如果您一开始就使用 rand(),那么极少的偏斜(对于 max_n-min_n 相对较小)是您最不必担心的问题。 @user168715:因为这种方法不会映射到这种偏差可能很重要的像样的随机数实现。【参考方案2】:这实际上比大多数人意识到的要真正正确要困难一些:
int rand_lim(int limit)
/* return a random number between 0 and limit inclusive.
*/
int divisor = RAND_MAX/(limit+1);
int retval;
do
retval = rand() / divisor;
while (retval > limit);
return retval;
尝试仅使用%
(或等价的/
)来获取范围内的数字几乎不可避免地会引入偏差(即,某些数字会比其他数字更频繁地生成)。
至于为什么使用%
会产生偏斜的结果:除非您想要的范围是 RAND_MAX 的除数,否则偏斜是不可避免的。如果你从小数字开始,很容易看出原因。考虑拿 10 块糖果(我们假设你不能将它们切成小块)并尝试将它们平均分配给三个孩子。显然这是做不到的——如果你把所有的糖果都分发出去,你能得到的最接近的结果是两个孩子得到三块糖果,其中一个得到四块。
只有一种方法可以让所有孩子获得相同数量的糖果:确保您根本不分发最后一块糖果。
为了将其与上面的代码联系起来,让我们首先将糖果从 1 到 10 编号,将孩子从 1 到 3 编号。最初的除法是因为有三个孩子,所以我们的除数是 3。然后,我们从桶中随机取出一颗糖果,查看它的数字并除以 3,然后将其交给那个孩子——但如果结果大于 3(即我们选择了 10 号糖果),我们就不会把它分发出去——我们把它扔掉,然后再挑一个糖果。
当然,如果您使用的是 C++ 的现代实现(即支持 C++11 或更高版本的实现),您通常应该使用标准库中的 distribution
类之一。上面的代码与std::uniform_int_distribution
最接近,但标准库还包括uniform_real_distribution
以及一些非均匀分布的类(伯努利、泊松、正态,也许还有几个我不记得的其他分布)时刻)。
【讨论】:
对不起,但是 ewww!我想做的最后一件事是在尝试获取随机数时循环划分一个不确定的数字(谁知道,也许永远)。倾斜与否,我将对此采取更简单的或者可能是表格驱动的解决方案。 @Michael:在你得出任何结论之前先尝试一下。事实上,“不确定数”通常是 1。除非你在一个真正紧密的循环中执行此操作(例如,用随机数填充向量),否则几乎不可能测量这比明显错误的版本慢。 这在技术上是正确的,但是你有一个从 rand() 开始的 GIGO 问题。当限制不是 RAND_MAX 的一个因素时,您似乎正在尝试纠正偏斜,使用模块化除法方法,您的错误约为limit / RAND_MAX
,直到 limit
接近 RAND_MAX
。从像 Rand() 这样的矮化效果开始的 PRNG 问题。您付出的代价是引入了一个具有无限运行时间的非确定性循环[IRL,它运行一次,但我们在这里分裂头发;-)] 你什么也得不到,因为 Rand 一开始就是垃圾。
不,不,我明白为什么其他人都错了,这是一个很好的解决方案。但是,我来自嵌入的土地,直到最近,还是很慢。将其与 rand() 调用相结合,该调用也趋于缓慢(更不用说随机性足够大,以至于将它们循环起来给我的胃带来不好的感觉),您可以看到我的立场。乍一看,我还担心这可能不是确定性的,但确实如此。呸,这里只是要习惯 21 世纪的编码。
@Philip Regan:偏斜来自取模后的小余数。假设您的随机数生成器生成 11 个值 0 - 10,然后您使用这些数字 mod 5 给您一个介于 0 和 4 之间的数字。有两种方法可以获得 3(3 和 8),但三种方法可以获得 0 (0, 5, 10) 所以最终结果不统一。这是一种真实的效果,但我认为它被其他使用 PRNG 的更大问题的噪音所淹没。【参考方案3】:
我专门用 Obj-C 为一个 iPhone 项目写了这个:
- (int) intInRangeMinimum:(int)min andMaximum:(int)max
if (min > max) return -1;
int adjustedMax = (max + 1) - min; // arc4random returns within the set min, (max - 1)
int random = arc4random() % adjustedMax;
int result = random + min;
return result;
使用方法:
int newNumber = [aClass intInRangeMinimum:1 andMaximum:100];
加盐调味
【讨论】:
该解决方案仍然存在模运算引入的偏差。由于您使用的是 arc4 库,因此它为您提供了您想要的名为“arc4random_uniform”的例程,该例程可以提供适当的统一结果。只需将一行更改为 int random = arc4random_uniform(adjustedMax);【参考方案4】:对于 [min,max) 范围内的整数值:
double scale = (double) (max - min) / RAND_MAX;
int val = min + floor(rand() * scale)
【讨论】:
对于新手,您必须包含#include <math.h>
【参考方案5】:
+(NSInteger)randomNumberWithMin:(NSInteger)min WithMax:(NSInteger)max
if (min>max)
int tempMax=max;
max=min;
min=tempMax;
int randomy=arc4random() % (max-min+1);
randomy=randomy+min;
return randomy;
我在我制作的一个与随机数相关的类中使用了这个方法。可以很好地满足我的非苛刻需求,但可能在某些方面存在偏见。
【讨论】:
这看起来更像是 Objective-C 而不是纯 C。以上是关于生成范围内的随机数? [复制]的主要内容,如果未能解决你的问题,请参考以下文章