我正在运行一系列物理模拟,其中我需要随机数。我正在使用C ++中的标准rand()
函数。
所以它的工作原理如下:首先,我为一组不同的1/(1+exp(a))
预先计算了a
形式的一堆概率。它们是由double
库中的exp
函数返回的类型math
,然后事情必定发生在那些概率中,只有两个,所以我生成一个随机的数均匀分布在0和1之间,并与那些预先计算的概率进行比较。为此,我使用了:
double p = double(rand()%101)/100.0;
所以我给出了0
和1
之间的随机值。这并没有产生正确的物理结果。我试过这个:
double p = double(rand()%1000001)/1000000.0;
这很有效。我真的不明白为什么所以我想要一些关于如何做的标准。我的直觉告诉我,如果我做了
double p = double(rand()%(N+1))/double(N);
N
足够大,使得最小的分割(1/N
)远小于最小概率1/1+exp(a)
,那么我将得到逼真的随机数。
我想理解为什么。
答案 0 :(得分:1)
rand()
返回0到RAND_MAX之间的随机数。
因此你需要这个:
double p = double(rand() % RAND_MAX) / double(RAND_MAX);
同时运行此代码段,您就会明白:
int i;
for (i = 1; i < 30; i++)
{
int rnd = rand();
double p0 = double(rnd % 101) / 100.0;
double p1 = double(rnd % 1000001) / 1000000.0;
printf ("%d\t%f\t%f\n", rnd, p0, p1);
}
for (i = 1; i < 30; i++)
{
int rnd = rand();
double p0 = double(rnd) / double(RAND_MAX);
printf ("%d\t%f\n", rnd, p0);
}
答案 1 :(得分:1)
你有很多问题。
rand()
根本不是随机的。在几乎所有的操作系统上,它都会返回分布严重,可怕的偏差数字。实际上很难找到一个好的随机数生成器,但我可以向你保证rand()
将是你能找到的最差的。
rand() % N
给出了有偏见的分布。想想鸽笼原理。让我们简化它,假设rand返回数字[0,7]并且你的N是6. 0到5映射到0到5,6映射到0和7映射到1,意味着0和1是两次很可能会出来。
在分割之前将数字转换为双精度不会从2中删除偏差,它只会使其不太明显。无论你做什么转换,鸽子原则都适用。
将分布均匀的随机数从整数转换为float / double比看起来更难。简单划分忽略了浮点数学如何工作的问题。
我无法帮助你1
,你需要做研究。查看随机数库的网络。如果你想要一些非常随机和不可预测的东西,你需要寻找加密随机库。如果你想要一个可重复但好的随机数Mersenne Twister应该足够好了。但你需要在这里做研究。
对于2和3,有标准解决方案。您正在将一组从M个元素映射到N个元素,而rand % N
仅在iff N&lt; M和N和M共享主要因素。因为在大多数系统中,M将是2的幂,这意味着N也必须是2的幂。因此,假设M是2的幂,算法是:找到高于或等于N的2的最近幂,让我们称之为P.生成randomness_source() % P
。如果数字高于N,请将其丢弃并重试。这是唯一安全的方法。比你和我更聪明的人在这个问题上花费了多年时间,没有更好的方法来消除这种偏见。
对于4,你可以忽略这个问题并且只是划分,在绝大多数情况下,这应该是足够好的。如果你真的想研究这个问题,我已经完成了一些工作并发布了代码on github.在那里,我将介绍浮点数如何工作的基本原理以及它与生成随机数的关系。
答案 2 :(得分:0)
// produces pseudorandom bits. These are NOT crypto quality bits. Has the same underlying unpredictability as uncooked
// rand() output. It buffers rand() bits to produce a more convenient zero-to-the-argument range including negative
// arguments, corrects for the toward-zero bias of the modular construction I'd be using otherwise, eliminates the
// RAND_MAX range limitation, (use INT64_MAX instead) and effectively obscures biases and sequence telltales due to
// annoyingly bad rand libraries. It does not correct these biases; anyone tracking the arguments and outputs has
// enough information to reconstruct the rand() output and detect them. But it makes the relationships drastically more complicated.
// needs stdint, stdlib.
int64_t privaterandom(int64_t range, int reset){
static uint64_t state = 0;
int64_t retval;
if (reset != 0){
srand((unsigned int)range);
state = (uint64_t)range;
}
if (range == 0) return (0);
if (range < 0) return -privaterandom(-range, 0);
if (range > UINT64_MAX/0xFFFFFFFF){
retval = (privaterandom(range/0xFFFFFFFF, 0) * 0xFFFFFFFF); // order of operations matters
return (retval + privaterandom(0xFFFFFFFF, 0));
}
while (state < UINT64_MAX / 0xFF){
state *= RAND_MAX;
state += rand();
}
retval = (state % range);
// makes "pigeonhole" bias alternate unpredictably between toward-even and toward-odd
if ((state/range > (state - (retval) )/ range) && state % 2 == 0) retval++;
state /= range;
return retval;
}
int64_t Random(int64_t range){ return (privaterandom(range, 0));}
int64_t Random_Init(int64_t seed){return (privaterandom(seed, 1));}