我想手动生成随机数。我知道每种编程语言都有rand或random函数,但我很好奇它的工作原理。 有人有相关代码吗?
POSIX.1-2001提供了rand()
和srand()
的一个实现示例,当需要在两台不同的计算机上获得相同的序列时,可能会有用。
static unsigned long next = 1;
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned seed) {
next = seed;
}
static void Main()
{
DateTime currentTime = DateTime.Now;
int maxValue = 100;
int hour = currentTime.Hour;
int minute = currentTime.Minute;
int second = currentTime.Second;
int milisecond = currentTime.Millisecond;
int randNum = (((hour + 1) * (minute + 1) * (second + 1) * milisecond) % maxValue);
Console.WriteLine(randNum);
Console.ReadLine();
}
你所说的手动是指“不使用计算机”还是“编写自己的代码”?
如果你不使用计算机,可以使用像骰子、袋中数字以及电视上选择团队、赢得Bingo系列等方法。拉斯维加斯充斥着这些用于给你带来糟糕赔率和ROI的过程(游戏)中使用的方法。你也可以获取伟大的RAND书,并翻到随机选择的页面:
http://www.amazon.com/Million-Random-Digits-Normal-Deviates/dp/0833030477
(此外,为了一些娱乐,阅读评论)
如果您要编写自己的代码,则需要考虑为什么不使用系统提供的RNG不够好。如果您正在使用现代操作系统,则用户程序将有一个RNG可用,应该足以满足您的应用程序。
如果您确实需要实现自己的RNG,则有大量的生成器可供选择。对于非安全使用,您可以查看LFSR链、同余生成器等。无论您需要哪种分布(均匀分布、正态分布、指数分布等),都应该能够找到算法描述和实现库。
对于安全使用,您应该查看像Yarrow/Fortuna、NIST SP 800-89指定的PRNG和RFC 4086这样需要提供良好熵源来馈送PRNG的内容。或者更好的是,使用操作系统中的那个应该满足安全RNG要求。
RNG的实现可能是一项有趣的练习,但很少需要。不要发明自己的算法,除非它是为玩具应用程序而设计的。不要为安全应用(例如生成加密密钥)发明RNG,除非您做了一些认真的阅读和调查。你会感谢我的(我希望)。
梅森旋转算法的周期非常长(2^19937-1)。
下面是一个非常基本的C++实现:
struct MT{
unsigned int *mt, k, g;
~MT(){ delete mt; }
MT(unsigned int seed) : mt(new unsigned int[624]), k(0), g(0){
for (int i=0; i<624; i++)
mt[i]=!i?seed:(1812433253U*(mt[i-1]^(mt[i-1]>>30))+i);
}
unsigned int operator()(){
unsigned int q=(mt[k]&0x80000000U)|(mt[(k+1)%624]&0x7fffffffU);
mt[k]=mt[(k+397)%624]^(q>>1)^((q&1)?0x9908b0dfU:0);
unsigned int y = mt[k];
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680U;
y ^= (y << 15) & 0xefc60000U;
y ^= (y >> 18);
k = (k+1)%624;
return y;
}
};
如果你想自己手动编写一个随机生成器,我无法为你提供效率,但我可以为你提供可靠性。我实际上决定编写一些使用时间进行计数以测试计算机处理速度的代码,并借此编写了自己的随机数生成器,使用取模算法进行计数(计数为随机的)。请自行尝试并在大型测试集中测试数字分布。顺便说一下,这是用Python编写的。
def count_in_time(n):
import time
count = 0
start_time = time.clock()
end_time = start_time + n
while start_time < end_time:
count += 1
start_time += (time.clock() - start_time)
return count
def generate_random(time_to_count, range_nums, rand_lst_size):
randoms = []
iterables = range(range_nums)
count = 0
for i in range(rand_lst_size):
count += count_in_time(time_to_count)
randoms.append(iterables[count%len(iterables)])
return randoms