我正在为一个科学项目尝试在C#中获取随机布尔值。问题是,布尔值为真的几率必须在10^-12到10^-14左右; 默认的随机函数只生成整数,并且0和[u]int.max之间的值远远不够大。
如何生成具有如此低的真实几率的随机布尔值?
编辑
正如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 之间的 double 类型数值。
var r = new Random();
var probablyFalseBool = r.NextDouble() < 0.0000000000001;
如有必要,请更改零的数量。
var probablyFalseBool = r.Next(0,Int32.MaxValue) == 0
相同的结果,因为Random.Next
调用与Random.NextDouble
调用相同的受保护的Sample
方法。 - KyleNextDouble
方法的分辨率为 1/Int32.MaxValue
(约 1/20亿),因此在需要更高分辨率时不足以使用。 - MatthewNextDouble()
来实现这个目的。 - Rik尝试将多个随机选择结合起来:
if(rnd.Next(0,10000) == 0 && rnd.Next(0,10000) == 0 && rnd.Next(0,10000) == 0){
}
我不确定C#语法是否正确,但这个if块有10^-12的概率会被执行。
NextBytes
方法来获取大的随机数。true
的概率为2.842e-14: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;
正如Nathan所建议的那样,您可以使用Next
方法来指定结果的范围。
然后,您可以使用&&
运算符来确保它达到您的精度要求。
// 1 in a million
var result = random.Next(0, 1000) == 0 && random.Next(0, 1000) == 0;
var result = rnd.Next(0,100) == 0;
result
为真的概率为100分之1。您可以轻松地将值调整为所需的任何概率。Next
方法不具有足够的精度。 - MatthewNext()
方法不包含足够的精度 - 参数类型不足以容纳值为10,000,000,000,000。 - qJake多维度的Go!一个正常的随机数在一维(即沿着一条线)。通过将两个随机数相乘,您使用了两个维度,依此类推。
如果您取6个1到100之间的随机整数,然后将它们相乘,得到结果为1的概率是10^12中的1。同样,对于4个1到1000之间的随机整数或3个1到10000之间的随机整数也是如此。
如果您想要像10^12中的30这样的结果,则使用1到1,000,000之间的两个随机数,并且您希望其中一个是1,另一个小于等于30。
如果您想要10^12中的x(<1,000,000)这样的结果,则使用1到1,000,000之间的两个随机数,并且您希望其中一个是1,另一个小于等于x。
生成两个相邻的整数表示
(target_value div int_max, target_value mod int_max)
检查第一个参数是否为0
,第二个参数是否小于desired_precison * int_max
。
如果您对引入偏差有疑虑,请在测试前随机交换一对整数的顺序。
下面是示例代码,展示了这种技术(已经在这里进行过测试):
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");
}
}
}
chance = 2.5 * Math.Pow(10, -12) * (((tdx21+tdx12)/2)*(30/3.6)) + ((2949768/(5.1*(Math.Pow(10, -14))))*(157766400^-1)) * (((tdx21+tdx12)/2)*(30/3.6));
;不适用于基准测试。 - Sebb你可以使用Round.NextDouble或Round.NextBytes来获取更广泛的范围,而不是使用Round.Next
。
使用NextBytes
,你可以使用4-5字节的缓冲区来获取所需的范围。大致上,你可以像这样做:
var buffer=new byte[5];
rnd.NextBytes(buffer);
return buffer.All(b=>b>0);
使用BitArray可能可以让这个过程更快。
如果使用NextDouble
,则需要检查结果是否小于1 / 10^12。
NextBytes
,您可以获得更大的值范围 - Panagiotis Kanavos