Objective-C中的非均匀随机数

时间:2013-02-06 20:46:48

标签: objective-c c random

我想计算[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;

2 个答案:

答案 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);
}