在一定范围内生成随机双精度浮点数

5

我目前在生成-32.768到32.768之间的随机数方面遇到了麻烦。它总是给我相同的值,但小数点后面有微小变化,例如:27.xxx。

这是我的代码,请帮忙看看。

#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;

int main()
{
    srand( time(NULL) );
    double r = (68.556*rand()/RAND_MAX - 32.768);
    cout << r << endl;
    return 0;
}

你尝试过使用循环吗?由于time(NULL)在相邻的秒之间变化不大,所以有可能每次得到相同的数字。gettimeofday()的微秒计数可能会更好地工作。 - Mats Petersson
将连续的值传递给srand通常不会导致从第一次调用rand开始就得到相邻的结果。(虽然由于对rand质量没有实际要求,你的体验可能会有所不同。) - aschepler
5个回答

12

如果您使用的是C++11编译器,则可以使用类似于以下内容的代码,这些代码实际上更易于阅读且更难出错:

#include <random>
#include <iostream>
#include <ctime>


int main()
{
    //Type of random number distribution
    std::uniform_real_distribution<double> dist(-32.768, 32.768);  //(min, max)

    //Mersenne Twister: Good quality random number generator
    std::mt19937 rng; 
    //Initialize with non-deterministic seeds
    rng.seed(std::random_device{}()); 

    // generate 10 random numbers.
    for (int i=0; i<10; i++)
    {
      std::cout << dist(rng) << std::endl;
    }
    return 0;
}

正如bames53所指出的那样,如果您充分利用c++11,上述代码甚至可以更短:
#include <random>
#include <iostream>
#include <ctime>
#include <algorithm>
#include <iterator>

int main()
{
    std::mt19937 rng; 
    std::uniform_real_distribution<double> dist(-32.768, 32.768);  //(min, max)
    rng.seed(std::random_device{}()); //non-deterministic seed
    std::generate_n( 
         std::ostream_iterator<double>(std::cout, "\n"),
         10, 
         [&]{ return dist(rng);} ); 
    return 0;
}

我需要指定的范围。如果我想要那个范围,我会使用(int)。 - Olivier
1
不过,你也应该更改normal_dist的名称,因为它只能与std::normal_distribution或类似函数一起使用。(正态分布也称为高斯分布。) - bames53
哈哈,真不敢相信我居然错过了那个。已经更新了 :) - Carl
请注意,uniform_real_distribution在[min,max)范围内生成数字,即不会生成最大值。 - elegant dice

0

另外,如果您没有使用C++11,您可以使用以下函数:

double randDouble(double precision, double lowerBound, double upperBound) {
 double random;
 random = static_cast<double>(((rand()%(static_cast<int>(std::pow(10,precision)*(upperBound - lowerBound) + 1))) + lowerBound*std::pow(10,precision)))/std::pow(10,precision);
 return random;
}

-1
我已经在你的程序中添加了一个 for 循环:
#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;

int main () {
    srand(time (NULL));

    for (int i = 0; i < 10; ++i) {
        double r = ((68.556 * rand () / RAND_MAX) - 32.768);

        cout << r << endl;
    }

    return 0;
}

示例输出:

 31.6779 
-28.2096
 31.5672
 18.9916 
-1.57149 
-0.993889
-32.4737
 24.6982
 25.936 
 26.4152

在我看来,一切都还好。我已经为您添加了 Ideone 上的代码。

这里有四次运行:

 Run 1:
    -29.0863
    -22.3973
     34.1034
    -1.41155
    -2.60232
    -30.5257
     31.9254
    -17.0673
     31.7522
     28.227

Run 2:
    -14.2872
    -0.185124
    -27.3674
     8.12921
     22.4611
    -0.414546
    -21.4944
    -11.0871
     4.87673
     5.4545

Run 3:
    -23.9083
    -6.04738
    -6.54314
     30.1767
    -16.2224
    -19.4619
     3.37444
     9.28014
     25.9318
    -22.8807

Run 4:
     25.1364
     16.3011
     0.596151
     5.3953
    -25.2851
     10.7301
     18.4541
    -18.8511
    -0.828694
     22.8335

也许你在运行之间没有等待至少一秒钟?


我知道这个程序可以运行,但是当你再次运行程序时,它会给出完全相同的循环,只是小数点后面的数字有所变化。它会给出完全相同的循环。 - Olivier
我的示例输出看起来像ideone上的输出吗?我再次运行它,得到了“30.3961 -13.9189 14.837 25.0323 -7.88294 24.9879 3.77392 18.4251 -8.11763 35.4337”,然后是“25.0197 31.0387 -10.2659 -8.66796 -28.1792 -6.34876 7.51343 -32.6934 -23.4206 -16.8222”。除非你在运行之间等待不到一秒钟,否则我不确定你做错了什么,但问题不在你的代码中。 - David Schwartz
是的,我从ideone复制了你的代码。唯一的问题是循环中的第一个值总是相同的(小数点后有微小变化)。其余的是随机的。 - Olivier
听起来你的伪随机数生成器质量很低。尝试在程序开头添加一个额外的 rand() 调用。(但是,老实说,如果你有任何要求,请不要使用 rand()。它没有质量保证。) - David Schwartz
是的!出于某种原因它起作用了。在我的主程序中,我不得不加入一个无用的rand()浮点数才能使一切正常运行,有点奇怪。非常感谢! - Olivier

-1

所以,我认为这是一个典型的例子,“使用time(NULL)来生成接近的随机数序列不是一个好的方法”。从一次调用到下一次调用中,time(NULL)改变的位数并不多,因此生成的随机数相当相似。这不是一个新现象 - 如果你在谷歌上搜索“我的随机数不太随机”,你会发现很多这样的情况。

有几种不同的解决方案 - 获取微秒或纳秒时间将是最简单的选择 - 在Linux中,gettimeofday将作为结构体的一部分给出微秒时间。


-1

看起来很明显,但有些例子却说不同...但我认为当你用一个整数除以另一个整数时,你总是得到一个整数?并且你需要将每个整数强制转换为double/float,然后再将它们相除。

例如:double r = (68.556* (double)rand()/(double)RAND_MAX - 32.768);

此外,如果你每次调用rand()都调用srand(),你会重置种子,导致每次返回的值都是相似的,而不是“随机”的。


代码不执行整数除法;68.556*rand()/RAND_MAX 就像 (68.556*rand())/RAND_MAX,这意味着分子是一个 double - bames53
啊,从左到右,我明白了。我还是会把它放在那里,以避免日后更改代码时出现意想不到的问题。 - Sellorio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接