随机生成的机会非常低

时间:2014-05-07 15:52:43

标签: c# random

我试图在C#中为一个科学项目获得一个随机的bool。问题是布尔值为真的几率必须在10 ^ -12到10 ^ -14之间;默认随机函数只生成整数,0和[u]之间的值int.max远小。

如何生成一个随机布尔值,其真实可能性很小?

8 个答案:

答案 0 :(得分:15)

编辑

Random.NextDouble()不会给出预期的结果!

正如Kyle在下面的评论中建议的那样,Random.NextDouble()的实施将int映射到区间[0.0,1.0],有效地使我的代码等同于r.Next( 0, Int32.MaxValue ) == 0 。添加更多的零不会影响结果为假的概率。

使用其他答案之一,或使用此代码从System.Random生成ulong(范围0-18446744073709551615)。

var r = new Random();
var bytes = new byte[8];
r.NextBytes(bytes);
ulong result = BitConverter.ToUInt64(bytes, 0);

原始答案

警告:无法按预期工作,请勿使用!仅为上下文提供。


改为使用Random.NextDouble():结果是介于0.0和1.0之间的双倍

var r = new Random();
var probablyFalseBool = r.NextDouble() < 0.0000000000001;

如有必要,可以改变零的数量。

答案 1 :(得分:15)

尝试组合多个随机选择:

if(rnd.Next(0,10000) == 0 && rnd.Next(0,10000) == 0 && rnd.Next(0,10000) == 0){
}

不确定C#语法是否正确,但是输入if块的概率为10 ^ -12。

答案 2 :(得分:3)

您可以使用NextBytes方法获取较大的随机数。

例如,这将给出2.842e-14概率,即布尔值为true

Random r = new Random();
byte[] buffer = new byte[6]; // make an array with 48 bits
r.NextBytes(buffer);
buffer[0] &= 0xf8; // mask out three bits to make it 45
bool occured = buffer.Sum(b => b) == 0;

答案 3 :(得分:2)

正如Nathan建议的那样,您可以使用Next方法指定结果范围。

然后,您可以使用&&运算符来确保它符合您的精确度。

// 1 in a million
var result = random.Next(0, 1000) == 0 && random.Next(0, 1000) == 0; 

然后您可以更改它们以获得所需的费率。

答案 4 :(得分:1)

您可以轻松控制这样的几率:

var result = rnd.Next(0,100) == 0;

这样可以使result的赔率为真100分。您可以轻松地将值调整到您想要的任何赔率。

答案 5 :(得分:1)

多维度!正常的随机数是单个维度(即沿着一条线)。通过将两个随机数相乘,您将使用两个维度,依此类推。

如果你取1到100之间的6个随机整数,那么将它们相乘得到结果1的概率是10 ^ 12中的1。与1到1000之间的4个随机整数相同,或者1到10000之间的3个随机整数。

如果您想要10 ^ 12中的30,那么请使用1到1,000,000之间的两个随机数,并且您希望一个为1而另一个为30或更少。

如果您想要10 ^ 12中的x(<1,000,000),那么请使用介于1和1,000,000之间的两个随机数,并且您希望一个为1而另一个为x或更小。

答案 6 :(得分:0)

连续生成两个整数,表示

(target_value div int_max, target_value mod int_max)

选中较大的0,第二个小于desired_precison * int_max

如果您对引入偏差有疑问,请在测试前将两个整数的顺序随机化。

此独立代码说明了该技术(已测试here):

using System.IO;
using System;

class Program
{
    static void Main(string[] args)
    {
        bool   flip, strike;
        int    eps, lo, hi;
        Random rnd;

        eps = Int32.Parse(args[0]); // whatever is appropriate

        rnd = new Random();
        lo = rnd.Next(Int32.MaxValue);
        hi = rnd.Next(Int32.MaxValue);
        flip = (rnd.Next() > 0.5); 
        if (flip) { int swap; swap = lo; lo = hi; hi = swap; }

        strike = (hi == 0) && (lo < eps);

        Console.Write("[hi lo] = ");
        Console.Write(hi);
        Console.WriteLine(lo);
        if (strike) {
            Console.WriteLine("strike");
        }
    }
}

答案 7 :(得分:0)

而不是Round.Next,您可以使用Round.NextDoubleRound.NextBytes来获得更广泛的范围。

使用NextBytes,您可以使用4-5字节的缓冲区来获得所需的范围。非常粗略,你可以这样做:

var buffer=new byte[5];
rnd.NextBytes(buffer);
return buffer.All(b=>b>0);

您可以使用BitArray

加快速度

使用NextDouble,您需要检查结果是否小于1/10 ^ 12.