我想计算[0, n - 1]
范围内的非均匀分布随机数。所以最小可能值为零。最大可能值为n-1。我希望最小值出现最频繁,最大值出现相对不频繁,并且之间的近似线性曲线(高斯也很好)。 如何在Objective-C中执行此操作? (可能使用基于C的API)
我当前想法的一个非常粗略的草图是:
// min value w/ p = 0.7
// some intermediate value w/ p = 0.2
// max value w/ p = 0.1
NSUInteger r = arc4random_uniform(10);
if (r <= 6)
result = 0;
else if (r <= 8)
result = (n - 1) / 2;
else
result = n - 1;
答案 0 :(得分:1)
如果您尝试平算arc4random_uniform()
的返回值(或乘以其中两个)会怎样?
int rand_nonuniform(int max)
{
int r = arc4random_uniform(max) * arc4random_uniform(max + 1);
return r / max;
}
我已经快速编写了一个用于测试它的示例程序,看起来很有希望:
int main(int argc, char *argv[])
{
int arr[10] = { 0 };
int i;
for (i = 0; i < 10000; i++) {
arr[rand_nonuniform(10)]++;
}
for (i = 0; i < 10; i++) {
printf("%2d. = %2d\n", i, arr[i]);
}
return 0;
}
结果:
0. = 3656
1. = 1925
2. = 1273
3. = 909
4. = 728
5. = 574
6. = 359
7. = 276
8. = 187
9. = 113
答案 1 :(得分:1)
我认为你基本上是正确的轨道。有可能存在精度或范围问题,但一般情况下如果你想随机选择,比如说3,2,1或0,你想要选择3的概率是选择0的概率的4倍然后是一个纸上练习,你可能正好在一个充满:
的网格中3 3 3 3
2 2 2
1 1
0
将东西扔到上面并读取它所在的数字。
所需线性比例的选项数量为:
- 1 if number of options, n, = 1
- 1 + 2 if n = 2
- 1 + 2 + 3 if n = 3
- ... etc ...
这是算术级数的简单总和。你最终会得到n(n + 1)/ 2个可能的结果。例如。对于n = 1,即1 * 2/2 = 1.对于n = 2,则为2 * 3/2 = 3.对于n = 3,则为3 * 4/2 = 6.
所以你会马上写下这样的东西:
NSUInteger random_linear(NSUInteger range)
{
NSUInteger numberOfOptions = (range * (range + 1)) / 2;
NSUInteger uniformRandom = arc4random_uniform(numberOfOptions);
... something ...
}
此时你只需决定uniform uniformRandom落入哪个bin。最简单的方法是使用最明显的循环:
NSUInteger random_linear(NSUInteger range)
{
NSUInteger numberOfOptions = (range * (range + 1)) / 2;
NSUInteger uniformRandom = arc4random_uniform(numberOfOptions);
NSUInteger index = 0;
NSUInteger optionsToDate = 0;
while(1)
{
if(optionsToDate >= uniformRandom) return index;
index++;
optionsToDate += index;
}
}
鉴于你可以在没有迭代的情况下计算出optionsToDate,一个明显更快的解决方案就是二元搜索。
更聪明的看法是uniformRandom是从(0,0)到(n,n)的线下面的框的总和。所以它是图表下方的区域,图形是一个简单的直角三角形。所以你可以从区域公式向后工作。
具体地,图中从(0,0)到位置x的(n,n)的区域是(x * x)/ 2。所以你正在寻找x,其中:
(x-1)*(x-1)/2 <= uniformRandom < x*x/2
=> (x-1)*(x-1) <= uniformRandom*2 < x*x
=> x-1 <= sqrt(uniformRandom*2) < x
在这种情况下,你想取x-1,因为结果没有进展到数字网格的下一个离散列。所以你可以使用平方根操作简单整数截断。
所以,假设我没有弄清楚我在路上的确切不等式,并假设所有精度都适合:
NSUInteger random_linear(NSUInteger range)
{
NSUInteger numberOfOptions = (range * (range + 1)) / 2;
NSUInteger uniformRandom = arc4random_uniform(numberOfOptions);
return (NSUInteger)sqrtf((float)uniformRandom * 2.0f);
}