C++ random_shuffle总是给出相同的结果

C++ random_shuffle is always giving the same results

提问人:Ana Echavarria 提问时间:10/5/2016 最后编辑:AmitAna Echavarria 更新时间:10/16/2023 访问量:1318

问:

以下对随机洗牌的调用总是为向量提供相同的结果v

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>


int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::srand(time(0));
    std::random_shuffle(v.begin(), v.end());

    for (int i = 0; i < v.size(); ++i) {
        printf("%d ", v[i]); printf("\n");
    }

    printf("%d\n", std::rand() % 100);
}

我试过使用

g++ -std=c++0x
g++ -std=c++11

但两者每次都给出相同的结果,所以我不太明白发生了什么。

$./a.out
7 1 4 6 8 9 5 2 3 10 
26
$ ./a.out
7 1 4 6 8 9 5 2 3 10 
41
$ ./a.out
7 1 4 6 8 9 5 2 3 10 
39
C C++11 libc++ 苹果叮当

评论

1赞 Mooing Duck 10/5/2016
你在哪里/什么时候打电话?你是如何测试的?srand(time(0));
0赞 Fantastic Mr Fox 10/5/2016
可能与 stackoverflow.com/questions/4926622/ 有关...
0赞 Jonathan Wakely 10/5/2016
欢迎来到 stackoverflow,当问“为什么这个代码不起作用”时,请提供一个完整的程序,这样我们就不必浪费时间添加你已经拥有的缺失代码。
1赞 fukanchik 10/5/2016
@AnaEchavarria它总是为我产生不同的结果。但是,如果在同一秒内启动,它必须始终生成相同的结果。
1赞 T.C. 10/5/2016
这是 clang/libc++。它们不用作随机性的来源。random_shufflerand

答:

4赞 Jonathan Wakely 10/5/2016 #1

首先,意思是完全一样的,所以测试两者是没有意义的。-std=c++0x-std=c++11

你没有提供一个完整的程序(请下次阅读 https://stackoverflow.com/help/mcve),所以我猜到了你的代码的其余部分,我试了一下:

#include <iostream>
#include <vector>
#include <algorithm>
#include <stdlib.h>

using namespace std;

int main()
{
  vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  srand(time(0));
  random_shuffle(v.begin(), v.end());

  for (int i : v)
    std::cout << i << ' ';
  std::cout << std::endl;
}

我每秒都会得到不同的结果:

tmp$ ./a.out
2 1 8 5 9 7 6 3 10 4 
tmp$ ./a.out
10 7 6 3 1 8 9 4 5 2 
tmp$ ./a.out
4 7 3 6 5 8 1 9 10 2 
tmp$ ./a.out
4 7 3 6 5 8 1 9 10 2 
tmp$ ./a.out
4 7 3 6 5 8 1 9 10 2 
tmp$ ./a.out
10 2 6 3 9 4 5 7 8 1 
tmp$ ./a.out
10 2 6 3 9 4 5 7 8 1 
tmp$ ./a.out
10 2 6 3 9 4 5 7 8 1 
tmp$ ./a.out
2 1 3 7 5 8 9 6 4 10 

它产生相同结果的次数是因为返回的秒数相同,因此函数的种子相同,因此结果相同。如果你等待一秒钟,以便返回一个不同的值,你应该得到一个不同的元素随机洗牌。time(0)rand()time(0)

如果您运行的代码与我的代码不同,您可能会得到不同的结果,但我们不可能解释结果,因为您没有向我们展示您的代码。

评论

0赞 Ana Echavarria 10/5/2016
谢谢乔纳森。我已经更新了问题以包含整个代码。我等待了一秒钟以上重新运行它,但仍然得到相同的结果。我知道它正在工作,因为如果我添加一个喜欢来打印它的值,每次都会产生不同的结果。只是产生了相同的结果。srand(time(0))rand()random_shuffle
8赞 T.C. 10/5/2016 #2

OP 的评论清楚地表明,这是他们正在使用的 Clang 和 libc++,而不是 GCC/libstdc++。

快速浏览一下 libc++ 的 random_shuffle 实现,就会发现它使用类型的对象作为其随机性的来源,而检查 __rs_default 的实现表明它只是使用默认构造的对象:__rs_defaultstd::mt19937

__rs_default::result_type
__rs_default::operator()()
{
    static mt19937 __rs_g;
    return __rs_g();
}

换言之,在此实现中,对 的双参数版本使用的“随机性”源没有任何影响。(可怕的引号,因为它总是使用固定的种子。请注意,这根本不需要使用,因此您无论如何都不能指望在可移植代码中“工作”。srandrandom_shufflerandom_shufflerandsrand

使用和设施代替。std::shuffle<random>

评论

0赞 Baum mit Augen 10/5/2016
如果由于某种原因(老师或类似原因)应该被禁止,您可以通过调用(也许是 mod smth.,如果需要很长时间,没有测试)次数来解决这个问题。不过,这确实是一个黑客,如果可能的话,使用这些东西,正如 TC 所说。<random>std::random_shuffletime()<random>
0赞 Amit 10/14/2023 #3

现代 C++

它不在标准中得到保证,这将依赖于.std::random_shufflestd::srand

--

脚注:在 C++14 中已弃用,并在 C++17 中删除。std::random_shuffle

由于 C++11(问题标有 ),因此最好使用,并且由于 C++20 使用 ,带有显式随机生成器。示例c++11std::shufflestd::ranges::shuffle

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>


int main() 
{
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::random_device rd;
    std::mt19937 gen(rd()); // Mersenne Twister generator. 

//  std::shuffle(v.begin(), v.end(), gen);
    std::ranges::shuffle(v, gen); // (Since C++20)
    
    for (const auto& i : v) {
        std::cout << i << std::endl;
    }
}