将 Int 均匀随机范围缩放为 Double 1
事实上,我有几个相互交织的问题。 (如果重要的话我会使用 C#。)
首先。我有一个 prng 可以生成 UInt32 范围内的随机数,从 0 到 UInt32.Max(包含在内)。我想尽可能保持一致性。获得 [a,b], (a,b) 双范围(例如 [0,1], [0,1), (0,1), [-2,4], (- 10,10))?
我担心的是以下几点。我有 4 294 967 296 prng 结果。它小于 [0,1] 双范围内的数字 — 2^53。所以我用2位数字构造了4 294 967 296进制数,它是随机且统一的[0, 4294967295 * 4294967296 + 4294967295]。这个最大值大于 1 上的 2^53,所以如果有人得到它,就把它扔掉,重新计算,使用 mod 2^53 并得到统一的数字,例如 [0,1]。这里我必须将最大值表示为 double (假设没有 Int64 类型)——它有什么缺点吗?
现在,如果我想要得到 [0,1),我认为结果的数量是 (2^53) - 1。添加到最后一个结果 1/(2^53) 将在 (0,1] 中产生随机双精度为了得到 (0,1) 我考虑 (2^53) - 2 个新结果并将 1/(2^53) 添加到基于 0 的结果,
但是如何获得接近或相等的双范围 ?到整个双范围?即使我像上面那样构建n元数,它也可能会变得大于Double.Max。可能有一些位移位/位掩码方法吗?
第二。 )是否可以得到 [Double.Min, Double.Max] 范围?总共有多少个双数?如果存在完整的双范围 prng,那么获得 UInt 范围的最佳方法是什么——“直接”映射或之前缩放到 [0,1]?
第三。我找到了这段代码(http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c):
/* generates a random number on [0,1) with 53-bit resolution*/
double genrand_res53(void)
{
unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
return(a*67108864.0+b)*(1.0/9007199254740992.0);
}
为什么a和b被转移到5和6并且为什么之后a*67108864.0+b是统一的?
谢谢。
Actually, I have several interweaving questions. (If it matters I use C#.)
First. I have a prng that generates random numbers in UInt32 range, from 0 to UInt32.Max inclusive. I want to preserve the uniformity as much as possible. What is the main idea to get [a,b], (a,b) double ranges (such as [0,1], [0,1), (0,1), [-2,4], (-10,10))?
I'm concerned about the following. I have 4 294 967 296 prng outcomes. It is less than numbers in [0,1] double range — 2^53. So I construct 4 294 967 296-ary number from 2 digits, which is random and uniform in [0, 4294967295 * 4294967296 + 4294967295]. This maximum value is larger than 2^53 on 1 so if one get it one throw it away, recalculate, use mod 2^53 and get uniform number in, for example, [0,1]. Here I have to represent the maximum value as double (suppose there is no Int64 type) — are there any drawbacks with it?
Now, if I want get [0,1), I consider that the number of outcomes is (2^53) - 1. Adding to the last result 1/(2^53) will produce random double in (0,1]. To get (0,1) I consider (2^53) - 2 new outcomes and add 1/(2^53) to 0-based result. Is all that correct?
But how to get double ranges that are close or equal to the whole double range? Even If I construct n-ary number like above, it may become larger than Double.Max. May be some bitshifts/bitmasks approach is possible?
Second. Now there is double prng with outcomes in [0,1) is that possible to get [Double.Min, Double.Max] range? How many double numbers at all? If there is full double range prng, what is the best way to get UInt range — map "directly" or scale to [0,1] before?
Third. I found this code (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c):
/* generates a random number on [0,1) with 53-bit resolution*/
double genrand_res53(void)
{
unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
return(a*67108864.0+b)*(1.0/9007199254740992.0);
}
Why a and b are shifted to 5 and 6 and why after that a*67108864.0+b is uniform?
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好的随机数生成器会在所有位置产生随机位。某些类别的较差的在低阶位中产生较差的随机性。因此,如果您需要 53 位并生成 64 位,则需要丢弃 11 个最低位 - 在您发布的示例代码中,5 位来自一个数字,6 位来自另一个数字。现在你有一个 26 位数字和一个 27 位数字; 2^26 是 67108864,2^53 是 9007199254740992,这应该解释为什么这些常量用于将这些数字缩放为 [0,1)。 (这是一个混合基数:第一个数字为 67108864-ary,第二个数字为 134217728-ary。)
(经常使用 53 位的原因是它使数字在减法时对称 - 否则,2 之间的值当你从 1 中减去 ^-53 和 2^-64 时,它们就会消失。)
此外,当你有太多位时,你不应该重新采样——只需扔掉多余的位(除非你的位少于一位)。
不管怎样,显而易见的方法给你[0,1)。如果你想要 (0,1],那就是 1 - [0,1)。如果您想要 (0,1),请在 a=0 和 b=0 时再次采样。如果您想要 [0,1],请注意,获得 1 的机会为 (2^53+1) 中的 1,否则您将获得 [0,1)。您可以通过在 [0,1) 中获取一个随机数并检查它是否为零,如果是,则选择 1 作为答案,或者如果不是,则从 [0,1) 中再次选择答案来近似这一点。无论如何,您的随机数生成器可能没有足够长的周期来比这更精确。
Good random number generators produce random bits at all positions. Certain classes of poor ones produce poor randomness in the lower order bits. Thus, if you need 53 bits and generate 64, you want to throw away the 11 lowest order bits--in the case of the example code you posted, 5 from one number and 6 from another. Now you have a 26 bit number and a 27 bit number; 2^26 is 67108864 and 2^53 is 9007199254740992, which should explain why those constants are used to scale those numbers into [0,1). (It's a mixed-base number: 67108864-ary for the first digit, and 134217728-ary for the second.)
(The reason 53 bits are often used is that it makes the numbers symmetric upon subtraction--otherwise, the values between 2^-53 and 2^-64 will disappear when you subtract them from 1.)
Also, you shouldn't resample when you have too many bits--just throw away surplus bits (unless you have less than one).
Anyway, the obvious method gives you [0,1). If you want (0,1] thats 1 - [0,1). If you want (0,1), sample again if you get both a=0 and b=0. If you want [0,1], note that there is a 1 in (2^53+1) chance of getting 1, and otherwise you have [0,1). You could approximate this by getting a random number in [0,1) and checking if it's zero, and picking 1 as the answer if so, or picking again from [0,1) if not. Your random number generator probably doesn't have a long enough period to be more exact than that anyway.