如何在c++中生成随机浮点数?
我想我可以用整数rand除以某个数,这足够了吗?
如何在c++中生成随机浮点数?
我想我可以用整数rand除以某个数,这足够了吗?
当前回答
drand48(3)是POSIX的标准方法。GLibC还提供了一个可重入版本drand48_r(3)。
该函数在SVID 3中被宣布过时,但没有提供足够的替代方案,因此IEEE Std 1003.1-2013仍然包含它,并且没有说明它将很快消失。
在Windows中,标准的方法是CryptGenRandom()。
其他回答
rand()可用于在c++中生成伪随机数。结合RAND_MAX和一点数学运算,您可以在任意选择的间隔内生成随机数。这对于学习目的和玩具程序来说是足够的。如果需要真正具有正态分布的随机数,则需要使用更高级的方法。
这将生成一个从0.0到1.0的数字。
float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
这将生成一个从0.0到任意浮点数X的数字:
float r2 = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/X));
这将生成一个从任意LO到任意HI的数字:
float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));
注意,如果需要真正的随机数,rand()函数通常是不够的。
在调用rand()之前,必须首先通过调用srand()来“播种”随机数生成器。这应该在程序运行期间执行一次,而不是在每次调用rand()时执行一次。通常是这样做的:
srand (static_cast <unsigned> (time(0)));
为了调用rand或srand,你必须#include <cstdlib>。
为了调用time,你必须#include <ctime>。
drand48(3)是POSIX的标准方法。GLibC还提供了一个可重入版本drand48_r(3)。
该函数在SVID 3中被宣布过时,但没有提供足够的替代方案,因此IEEE Std 1003.1-2013仍然包含它,并且没有说明它将很快消失。
在Windows中,标准的方法是CryptGenRandom()。
以Boost.Random为例。你可以这样做:
float gen_random_float(float min, float max)
{
boost::mt19937 rng;
boost::uniform_real<float> u(min, max);
boost::variate_generator<boost::mt19937&, boost::uniform_real<float> > gen(rng, u);
return gen();
}
尝试一下,您可能会更好地传递相同的mt19937对象,而不是每次都构造一个新的对象,但希望您能理解。
到目前为止,我对任何答案都不满意,所以我写了一个新的随机浮点函数。它对浮点数据类型进行了按位假设。它仍然需要一个rand()函数,至少有15个随机位。
//Returns a random number in the range [0.0f, 1.0f). Every
//bit of the mantissa is randomized.
float rnd(void){
//Generate a random number in the range [0.5f, 1.0f).
unsigned int ret = 0x3F000000 | (0x7FFFFF & ((rand() << 8) ^ rand()));
unsigned short coinFlips;
//If the coin is tails, return the number, otherwise
//divide the random number by two by decrementing the
//exponent and keep going. The exponent starts at 63.
//Each loop represents 15 random bits, a.k.a. 'coin flips'.
#define RND_INNER_LOOP() \
if( coinFlips & 1 ) break; \
coinFlips >>= 1; \
ret -= 0x800000
for(;;){
coinFlips = rand();
RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
//At this point, the exponent is 60, 45, 30, 15, or 0.
//If the exponent is 0, then the number equals 0.0f.
if( ! (ret & 0x3F800000) ) return 0.0f;
RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
}
return *((float *)(&ret));
}
在我看来,上面的答案确实给出了一些“随机”浮点数,但它们都不是真正的随机浮点数(即它们错过了浮点数表示的一部分)。在我进入我的实现之前,让我们先看看浮点数的ANSI/IEEE标准格式:
|符号(1位)| e(8位)| f(23位)|
这个词代表的数字是 (-1 *号)* 2^e * 1.f
注意“e”是一个有偏差的数字(偏差为127),因此范围从-127到126。最简单的(实际上也是最随机的)函数是将随机int类型的数据写入浮点数,因此
int tmp = rand();
float f = (float)*((float*)&tmp);
注意,如果你做浮动f = (float)rand();它将整数转换为浮点数(因此10将变成10.0)。 现在如果你想限制最大值你可以这样做(不确定是否有效)
int tmp = rand();
float f = *((float*)&tmp);
tmp = (unsigned int)f // note float to int conversion!
tmp %= max_number;
f -= tmp;
但是如果你观察浮点数的结构,你会发现浮点数的最大值大约是2^127,这比int数的最大值(2^32)要大得多,因此排除了很大一部分可以用浮点数表示的数字。 这是我的最终实现:
/**
* Function generates a random float using the upper_bound float to determine
* the upper bound for the exponent and for the fractional part.
* @param min_exp sets the minimum number (closest to 0) to 1 * e^min_exp (min -127)
* @param max_exp sets the maximum number to 2 * e^max_exp (max 126)
* @param sign_flag if sign_flag = 0 the random number is always positive, if
* sign_flag = 1 then the sign bit is random as well
* @return a random float
*/
float randf(int min_exp, int max_exp, char sign_flag) {
assert(min_exp <= max_exp);
int min_exp_mod = min_exp + 126;
int sign_mod = sign_flag + 1;
int frac_mod = (1 << 23);
int s = rand() % sign_mod; // note x % 1 = 0
int e = (rand() % max_exp) + min_exp_mod;
int f = rand() % frac_mod;
int tmp = (s << 31) | (e << 23) | f;
float r = (float)*((float*)(&tmp));
/** uncomment if you want to see the structure of the float. */
// printf("%x, %x, %x, %x, %f\n", (s << 31), (e << 23), f, tmp, r);
return r;
}
使用这个函数randf(0,8,0)将返回一个介于0.0和255.0之间的随机数