Scaling Int uniform random range into Double one

我与影子孤独终老i 提交于 2020-01-06 05:09:06

问题


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.


回答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.



来源:https://stackoverflow.com/questions/5472156/scaling-int-uniform-random-range-into-double-one

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!