Math.NET CryptoRandomSource接下来是有偏见的

时间:2016-08-18 08:34:34

标签: c# random mathdotnet

我正在开发一个受到严格监管审查的游戏平台。我之所以选择Math.NET,是因为它看起来很合适。不过,我刚从审计员那里收到了这条评论。

请注意这是否准确以及如何解决?

在RandomSource()中,Next(int,int)定义如下:

    public override sealed int Next(int minValue, int maxValue)
    {
        if (minValue > maxValue)
        {
            throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue);
        }

        if (_threadSafe)
        {
            lock (_lock)
            {
                return (int)(DoSample()*(maxValue - minValue)) + minValue;
            }
        }

        return (int)(DoSample()*(maxValue - minValue)) + minValue;
    }

这会以与以前相同的方式产生偏差。使用来自RNG的未缩放值并将其乘以该范围而不预先消除偏差(除非范围是2的幂,否则将存在偏差)。

2 个答案:

答案 0 :(得分:2)

更新 :在此讨论之后,Math.NET Numerics v3.13中的Next(minInclusive, maxExclusive)实现已更改。从v3.13开始,它不再涉及浮点数,而是采用具有所需位数的整数来支持所请求的范围(2的幂)并拒绝实际范围之外的那些。这样就避免了在字节采样本身之上添加任何偏差(例如由加密RNG提供)

假设:DoSample()返回[0,1)范围内的均匀分布样本(双精度浮点数)。

将其乘以范围R = max-min将导致[0,R)范围内的均匀分布样本。将其转换为整数(基本上是一个平面)将导致0,1,2,...,R-1之一的均匀分布的离散样本。在这一步中,我没有看到R是偶数,奇数或2的幂可能影响偏差的事实。

计算100'000'000样本的几次运行也没有表明明显的偏差,但当然这不是证明:

var r = new CryptoRandomSource();
long[] h = new long[8];
for (int i = 0; i < 100000000; i++)
{
    h[r.Next(2,7)]++;
}

0
0
19996313
20001286
19998092
19998328
20005981
0

0
0
20000288
20002035
20006269
19994927
19996481
0

0 
0 
19998296 
19997777 
20001463 
20002759 
19999705 
0 

答案 1 :(得分:0)

我已经为这个解决方案提供了0到最大值之间的值。我不是数学专家所以欢迎评论。

它似乎符合我所说的监管规范

2b)如果选择的特定随机数超出了重新缩放值的相等分布范围,则允许丢弃该随机数并按顺序选择下一个以进行重新缩放。“

    private readonly CryptoRandomSource _random = new CryptoRandomSource();

    private int GetRandomNumber(int max)
    {
        int number;
        var nextPowerOfTwo = (int)Math.Pow(2, Math.Ceiling(Math.Log(max) / Math.Log(2)));

        do
        {
            // Note: 2nd param of Next is an *exclusive* value. Add 1 to satisfy this
            number = _random.Next(0, nextPowerOfTwo + 1);
        } while (number > max);

        return number;
    }