C++ 随机浮点数生成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/686353/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:44:40  来源:igfitidea点击:

Random float number generation

c++randomfloating-point

提问by hasen

How do I generate random floats in C++?

如何在 C++ 中生成随机浮点数?

I thought I could take the integer rand and divide it by something, would that be adequate enough?

我以为我可以将整数 rand 除以某个值,这样就足够了吗?

回答by John Dibling

rand()can be used to generate pseudo-random numbers in C++. In combination with RAND_MAXand a little math, you can generate random numbers in any arbitrary interval you choose. This is sufficient for learning purposes and toy programs. If you need trulyrandom numbers with normal distribution, you'll need to employ a more advanced method.

rand()可用于在 C++ 中生成伪随机数。结合RAND_MAX和一点数学,您可以在您选择的任意间隔内生成随机数。这对于学习目的和玩具程序来说已经足够了。如果您需要具有正态分布的真正随机数,则需要采用更高级的方法。



This will generate a number from 0.0 to 1.0, inclusive.

这将生成一个从 0.0 到 1.0(含)的数字。

float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);

This will generate a number from 0.0 to some arbitrary float, X:

这将生成一个从 0.0 到某个任意的数字floatX

float r2 = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/X));

This will generate a number from some arbitrary LOto some arbitrary HI:

这将生成一个从一些任意LO到一些任意的数字HI

float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));


Note that the rand()function will often not be sufficient if you need truly random numbers.

请注意,rand()如果您需要真正的随机数,该函数通常是不够的。



Before calling rand(), you must first "seed" the random number generator by calling srand(). This should be done once during your program's run -- not once every time you call rand(). This is often done like this:

在调用之前rand(),您必须首先通过调用“播种”随机数生成器srand()。这应该在程序运行期间执行一次——而不是每次调用rand(). 这通常是这样完成的:

srand (static_cast <unsigned> (time(0)));

In order to call randor srandyou must #include <cstdlib>.

为了打电话rand还是srand必须的#include <cstdlib>

In order to call time, you must #include <ctime>.

为了打电话time,你必须#include <ctime>

回答by Shafik Yaghmour

C++11 gives you a lot of new options with random. The canonical paper on this topic would be N3551, Random Number Generation in C++11

C++11 为您提供了许多带有random. 关于这个主题的规范论文是N3551,C++11 中的随机数生成

To see why using rand()can be problematic see the rand() Considered Harmfulpresentation material by Stephan T. Lavavejgiven during the GoingNative 2013event. The slides are in the comments but here is a direct link.

要了解为什么使用rand()会出现问题,请参阅Stephan T. LavavejGoingNative 2013活动期间提供的rand() 被认为有害的演示材料。幻灯片在评论中,但这里有一个直接链接

I also cover boostas well as using randsince legacy code may still require its support.

由于遗留代码可能仍需要它的支持,因此我也涵盖了boost使用rand

The example below is distilled from the cppreference site and uses the std::mersenne_twister_engineengine and the std::uniform_real_distributionwhich generates numbers in the [0,10)interval, with other engines and distributions commented out (see it live):

下面的示例来自 cppreference 站点,并使用std::mersenne_twister_engine引擎和std::uniform_real_distribution[0,10)区间内生成数字,并注释掉其他引擎和发行版(实时查看):

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;

    //
    // Engines 
    //
    std::mt19937 e2(rd());
    //std::knuth_b e2(rd());
    //std::default_random_engine e2(rd()) ;

    //
    // Distribtuions
    //
    std::uniform_real_distribution<> dist(0, 10);
    //std::normal_distribution<> dist(2, 2);
    //std::student_t_distribution<> dist(5);
    //std::poisson_distribution<> dist(2);
    //std::extreme_value_distribution<> dist(0,2);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::floor(dist(e2))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

output will be similar to the following:

输出将类似于以下内容:

0 ****
1 ****
2 ****
3 ****
4 *****
5 ****
6 *****
7 ****
8 *****
9 ****

The output will vary depending on which distribution you choose, so if we decided to go with std::normal_distributionwith a value of 2for both meanand stddeve.g. dist(2, 2)instead the output would be similar to this (see it live):

输出将根据其分布您选择有所不同,所以,如果我们决定一起去的std :: normal_distribution与值2两者平均值STDDEVdist(2, 2)不是输出将与此类似(现场观看):

-6 
-5 
-4 
-3 
-2 **
-1 ****
 0 *******
 1 *********
 2 *********
 3 *******
 4 ****
 5 **
 6 
 7 
 8 
 9 

The following is a modified version of some of the code presented in N3551(see it live) :

以下是N3551实时查看)中部分代码的修改版本:

#include <algorithm>
#include <array>
#include <iostream>
#include <random>

std::default_random_engine & global_urng( )
{
    static std::default_random_engine u{};
    return u ;
}

void randomize( )
{
    static std::random_device rd{};
    global_urng().seed( rd() );
}

int main( )
{
  // Manufacture a deck of cards:
  using card = int;
  std::array<card,52> deck{};
  std::iota(deck.begin(), deck.end(), 0);

  randomize( ) ;  

  std::shuffle(deck.begin(), deck.end(), global_urng());
  // Display each card in the shuffled deck:
  auto suit = []( card c ) { return "SHDC"[c / 13]; };
  auto rank = []( card c ) { return "AKQJT98765432"[c % 13]; };

  for( card c : deck )
      std::cout << ' ' << rank(c) << suit(c);

   std::cout << std::endl;
}

Results will look similar to:

结果将类似于:

5H 5S AS 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC QD JD AH JC AC KD 9D 5C 2H 4H 9C 8C JH 5D 4S 7C AD 3S 8S TS 2C 8D 3H 6C JS 7S 6S

5H 5S AS 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC QD JD AH JC AC KD 9D 5C 2H 4H 9C 8C JH 7H 2D KS 3C 3C 3C 8S C 3D 3D 7S 6S

Boost

促进

Of course Boost.Randomis always an option as well, here I am using boost::random::uniform_real_distribution:

当然Boost.Random也总是一个选项,在这里我使用boost::random::uniform_real_distribution

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>

int main()
{
    boost::random::mt19937 gen;
    boost::random::uniform_real_distribution<> dist(0, 10);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::floor(dist(gen))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

rand()

兰特()

If you must use rand()then we can go to the C FAQfor a guides on How can I generate floating-point random numbers? , which basically gives an example similar to this for generating an on the interval [0,1):

如果您必须使用,rand()那么我们可以转到C 常见问题解答以获取有关如何生成浮点随机数的指南?,它基本上给出了一个与此类似的示例,用于在间隔上生成一个[0,1)

#include <stdlib.h>

double randZeroToOne()
{
    return rand() / (RAND_MAX + 1.);
}

and to generate a random number in the range from [M,N):

并在以下范围内生成一个随机数[M,N)

double randMToN(double M, double N)
{
    return M + (rand() / ( RAND_MAX / (N-M) ) ) ;  
}

回答by rlbond

Take a look at Boost.Random. You could do something like this:

看看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();
}

Play around, you might do better passing the same mt19937 object around instead of constructing a new one every time, but hopefully you get the idea.

随便玩玩,您可能会更好地传递相同的 mt19937 对象,而不是每次都构建一个新对象,但希望您能理解。

回答by Andreas DM

In modern c++you may use the <random>header that came with c++11.
To get random float's you can use std::uniform_real_distribution<>.

在现代c++,你可以使用<random>随来到头c++11
要获得随机数float,您可以使用std::uniform_real_distribution<>.

You can use a function to generate the numbers and if you don't want the numbers to be the sameall the time, set the engine and distribution to be static.
Example:

您可以使用函数来生成数字,如果您不希望数字始终相同,请将引擎和分布设置为 static.
例子:

float get_random()
{
    static std::default_random_engine e;
    static std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
    return dis(e);
}

It's ideal to place the float's in a container such as std::vector:

float's 放在容器中是理想的,例如std::vector

int main()
{
    std::vector<float> nums;
    for (int i{}; i != 5; ++i) // Generate 5 random floats
        nums.emplace_back(get_random());

    for (const auto& i : nums) std::cout << i << " ";
}

Example output:

示例输出:

0.0518757 0.969106 0.0985112 0.0895674 0.895542

回答by Ivan Prodanov

Call the code with two floatvalues, the code works in any range.

用两个float值调用代码,代码在任何范围内都有效。

float rand_FloatRange(float a, float b)
{
    return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}

回答by Rick

If you are using C++ and not C, then remember that in technical report 1 (TR1) and in the C++0x draft they have added facilities for a random number generator in the header file, I believe it is identical to the Boost.Random library and definitely more flexible and "modern" than the C library function, rand.

如果您使用的是 C++ 而不是 C,那么请记住,在技术报告 1 (TR1) 和 C++0x 草案中,他们在头文件中添加了用于随机数生成器的工具,我相信它与 Boost 相同。随机库,绝对比 C 库函数 rand 更灵活和“现代”。

This syntax offers the ability to choose a generator (like the mersenne twistermt19937) and then choose a distribution (normal, bernoulli, binomial etc.).

此语法提供了选择生成器(如梅森扭曲器mt19937)然后选择分布(正态、伯努利、二项式等)的能力。

Syntax is as follows (shameless borrowed from this site):

语法如下(无耻地从本站借来的):

  #include <iostream>
  #include <random>

  ...

  std::tr1::mt19937 eng;  // a core engine class 
  std::tr1::normal_distribution<float> dist;     

  for (int i = 0; i < 10; ++i)        
      std::cout << dist(eng) << std::endl;

回答by Joey

On some systems (Windows with VC springs to mind, currently), RAND_MAXis ridiculously small, i.?e. only 15 bit. When dividing by RAND_MAXyou are only generating a mantissa of 15 bit instead of the 23 possible bits. This may or may not be a problem for you, but you're missing out some values in that case.

在某些系统上(目前想到的RAND_MAX是带有 VC 的 Windows),它小得离谱,即 只有 15 位。当除以RAND_MAX你只生成一个 15 位的尾数而不是 23 个可能的位。这对您来说可能是也可能不是问题,但是在这种情况下您会遗漏一些值。

Oh, just noticed that there was already a comment for that problem. Anyway, here's some code that might solve this for you:

哦,刚注意到这个问题已经有评论了。无论如何,这里有一些代码可以为您解决这个问题:

float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);

Untested, but might work :-)

未经测试,但可能有效:-)

回答by ivan_pozdeev

drand48(3)is the POSIX standard way. GLibC also provides a reentrant version, drand48_r(3).

drand48(3)是POSIX标准方式。GLibC 还提供了一个可重入版本,drand48_r(3).

The function was declared obsolete in SVID 3 but no adequate alternative was provided so IEEE Std 1003.1-2013still includes it and has no notes that it's going anywhere anytime soon.

该函数在 SVID 3 中被宣布为过时,但没有提供足够的替代方案,因此IEEE Std 1003.1-2013仍然包含它,并且没有说明它很快就会去任何地方。

In Windows, the standard way is CryptGenRandom().

在 Windows 中,标准方法是CryptGenRandom()

回答by Mark Ransom

If you know that your floating point format is IEEE 754(almost all modern CPUs including Intel and ARM) then you can build a random floating point number from a random integer using bit-wise methods. This should only be considered if you do not have access to C++11's randomor Boost.Randomwhich are both much better.

如果您知道您的浮点格式是IEEE 754(几乎所有现代 CPU,包括 Intel 和 ARM),那么您可以使用按位方法从随机整数构建随机浮点数。仅当您无法访问 C++11randomBoost.Random两者都更好时才应考虑这一点。

float rand_float()
{
    // returns a random value in the range [0.0-1.0)

    // start with a bit pattern equating to 1.0
    uint32_t pattern = 0x3f800000;

    // get 23 bits of random integer
    uint32_t random23 = 0x7fffff & (rand() << 8 ^ rand());

    // replace the mantissa, resulting in a number [1.0-2.0)
    pattern |= random23;

    // convert from int to float without undefined behavior
    assert(sizeof(float) == sizeof(uint32_t));
    char buffer[sizeof(float)];
    memcpy(buffer, &pattern, sizeof(float));
    float f;
    memcpy(&f, buffer, sizeof(float));

    return f - 1.0;
}

This will give a better distribution than one using division.

这将提供比使用除法更好的分布。

回答by iNFiNiTyLoOp

I wasn't satisfied by any of the answers so far so I wrote a new random float function. It makes bitwise assumptions about the float data type. It still needs a rand() function with at least 15 random bits.

到目前为止,我对任何答案都不满意,所以我写了一个新的随机浮点函数。它对浮点数据类型进行按位假设。它仍然需要一个至少有 15 个随机位的 rand() 函数。

//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));
}