随机浮点数生成

has*_*sen 260 c++ random floating-point

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

我以为我可以把整数兰特除以某种东西,这足够了吗?

Joh*_*ing 363

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


这将生成从0.0到1.0(包括0.0和1.0)的数字.

float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
Run Code Online (Sandbox Code Playgroud)

这将生成一个从0.0到任意的数字float,X:

float r2 = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/X));
Run Code Online (Sandbox Code Playgroud)

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

float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));
Run Code Online (Sandbox Code Playgroud)

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


在呼叫之前rand(),您必须首先通过呼叫"播种"随机数生成器srand().这应该在程序运行期间完成一次 - 每次调用时都不会执行一次rand().这通常是这样做的:

srand (static_cast <unsigned> (time(0)));
Run Code Online (Sandbox Code Playgroud)

为了打电话randsrand你必须#include <cstdlib>.

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

  • 别忘了先播种! (21认同)
  • 我不明白为什么这么多人赞成这个答案.这在数学上是不正确的.RAND_MAX是一个非常小的数字(通常为2 ^ 16).这意味着从浮点的23位开始,你只能随机生成15位.其他人可能是零.你的确会得到均匀分布的随机数,但精度很低.例如,随机生成器可以生成0.00001和0.00002,但不能生成0.000017.因此,您的分布均匀,但精度较低(精度比实际浮点精度低256倍). (13认同)
  • 最好注意两个限制是包容性的. (12认同)
  • 这个答案有误导性.上周在Going Native 2013报道了它; rand()认为是有害的,http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful有一个非常详细的解释. (12认同)
  • @DanielHsH:OP特别询问可以使用什么机制用`rand()`生成随机浮点数.这个问题和我的答案都专注于学习基础知识,并不关心高精度.在学会跑步之前,你必须学会​​走路. (9认同)
  • @AdeMiller:它没有误导性,更不用说"完全错误"了.我明确地说,如果你需要真正随机的数字兰特是不够的.这个问题是根据*基本理解*提出的,正是在这种背景下提供了答案.在学习如何编程或玩具项目时,使用兰德并没有错. (5认同)
  • 选择从分母中划分而不是乘以除法的结果的原因是什么? (3认同)
  • 这是C++,所以你宁愿使用`<ctime>`. (2认同)

Sha*_*our 122

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

要了解为什么使用rand()可能会有问题,请参阅2013年GoingNative期间由Stephan T. Lavavej撰写rand()Considered Harmful演示材料.幻灯片在评论中,但这里是直接链接.

我还介绍boost和使用,rand因为遗留代码可能仍然需要它的支持.

下面的示例是从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';
    }
}
Run Code Online (Sandbox Code Playgroud)

输出将类似于以下内容:

0 ****
1 ****
2 ****
3 ****
4 *****
5 ****
6 *****
7 ****
8 *****
9 ****
Run Code Online (Sandbox Code Playgroud)

输出将根据您选择的分布有所不同,因此,如果我们决定一起去的std :: normal_distribution具有的价值2的两种意思STDDEVdist(2, 2)不是输出将与此类似(见直播):

-6 
-5 
-4 
-3 
-2 **
-1 ****
 0 *******
 1 *********
 2 *********
 3 *******
 4 ****
 5 **
 6 
 7 
 8 
 9 
Run Code Online (Sandbox Code Playgroud)

以下是一些代码的修改版本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;
}
Run Code Online (Sandbox Code Playgroud)

结果将类似于:

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

促进

当然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';
    }
}
Run Code Online (Sandbox Code Playgroud)

RAND()

如果你必须使用rand()那么我们可以去C FAQ获取指南如何生成浮点随机数?,基本上给出了一个类似的例子,用于在间隔上生成[0,1):

#include <stdlib.h>

double randZeroToOne()
{
    return rand() / (RAND_MAX + 1.);
}
Run Code Online (Sandbox Code Playgroud)

并生成以下范围内的随机数[M,N):

double randMToN(double M, double N)
{
    return M + (rand() / ( RAND_MAX / (N-M) ) ) ;  
}
Run Code Online (Sandbox Code Playgroud)


rlb*_*ond 60

看看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();
}
Run Code Online (Sandbox Code Playgroud)

玩转,你可能会更好地传递相同的mt19937对象,而不是每次构建一个新对象,但希望你能得到这个想法.

  • 这是C++ 11的一部分. (20认同)

Iva*_*nov 24

使用两个float值调用代码,代码适用于任何范围.

float rand_FloatRange(float a, float b)
{
    return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
Run Code Online (Sandbox Code Playgroud)


And*_* DM 22

在现代,c++您可以使用<random>随附的标题c++11.
要获得随机float的,你可以使用std::uniform_real_distribution<>.

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

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

将它放在float容器中是理想的,例如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 << " ";
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

0.0518757 0.969106 0.0985112 0.0895674 0.895542
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案,现在已经是 2020 年了。 (5认同)

Ric*_*ick 20

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

此语法提供了选择生成器(如mersenne twister mt19937)然后选择分布(正常,bernoulli,二项式等)的功能.

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

  #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;
Run Code Online (Sandbox Code Playgroud)

  • 这现在在 C++11 中,也可以使用最小值和最大值初始化 dist。 (2认同)

Joe*_*oey 5

在某些系统上(当前RAND_MAX,我想到的是VC弹簧的Windows),非常小,我.即 只有15位.除以时,RAND_MAX您只生成15位的尾数,而不是23位可能的位.这对您来说可能是也可能不是问题,但在这种情况下您错过了一些值.

哦,只是注意到已经有人对这个问题发表评论.无论如何,这里有一些代码可以解决这个问题:

float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);
Run Code Online (Sandbox Code Playgroud)

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

  • 在没有理论的情况下组成随机数要小心......对rand()的连续调用可能不是完全独立的.提示:如果它是一个线性同余生成器,则在连续调用时观察低位:它在0和1之间交替. (2认同)