random_shuffle和srand()每次都会给我相同的结果

random_shuffle and srand() give me the same result every time

本文关键字:结果 shuffle srand random      更新时间:2023-10-16

我试图对字母表的随机排列进行一些处理,但尽管使用srand(myseed),每个排列都会产生相同的结果
我已经包含了<algorithm>标头。

string create_permutation(unsigned seed)
{
    srand(seed);
    string permutation = ALPHABET;
    random_shuffle(permutation.begin(), permutation.end());
    return permutation;
}
cout << create_permutation(2) << endl; // or 3, 4, 5 etc
// continuously returns 'XQACKHSLOJ,TRBZNGV.W FIUEYDMP

如有任何帮助,我们将不胜感激。

编辑:最小、完整且可验证的示例

编辑2:对mcve 的调整

#include <iostream>
#include <algorithm>   
using namespace std;
const string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,' ";
string create_permutation(unsigned seed)
{
    srand(seed);
    string permutation = ALPHABET;
    random_shuffle(permutation.begin(), permutation.end());
    return permutation;
}
int main(){    
    cout << create_permutation(2) << endl; // or 3, 4, 5 etc
    // continuously returns 'XQACKHSLOJ,TRBZNGV.W FIUEYDMP
    return 0;
}

问题

  • 混洗不是随机的,因为shuffle_random每次被调用时都为随机数生成器使用相同的种子

srand不种子random_shuffle函数,它种子randrandom_shuffle通常调用rand,但不必

random_shuffle有两种形式:

  • 一个接受2个参数(开始/结束迭代器)

  • 一个需要3(开始/结束迭代器和一个随机生成器)。

您已经证明了您知道如何使用第一种形式,但第一种形式的问题在于,它在不同的平台和编译器中的实现方式不同。它可能根本不使用rand(),这是srand种子的函数。

您应该使用3参数形式,并提供随机数生成器作为函数的参数。

您可以按照这个详细的答案来学习如何制作自己的随机数生成器,也可以将rand()提供给random_shuffle函数作为随机数生成器。

  1. 当您为随机数生成器设定种子时,您为将提供伪随机数序列的算法设置起点。如果始终使用相同的种子,则算法将始终具有相同的起点,并且始终生成相同的数字序列
  2. 每次调用srand时,都会重置种子并重置算法的起点。
    1. 这里的一个常见错误是重复调用srand。除非你有充分的理由不这样做(如果你这样做了,你可能根本不应该使用rand和srand。看看<random>库),否则你应该在程序开始时调用srand一次,以便在使用该种子后对生成器进行一次种子设定
    2. CCD_ 18也相当昂贵。从性能的角度来看,您不想经常调用它

因此:由于对create_permutation的每次调用都使用seed参数调用srand,并且create_permutation总是使用相同的种子值调用,因此对于随机数生成器的给定实现,create_permutation将始终使用相同的随机数序列,从而生成相同的排列。

是一个快速的例子,只要程序运行频率不超过每秒一次,就会生成不同的排列

#include <iostream>
#include <string>
#include <algorithm>
#include <ctime>
const std::string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,' ";
std::string create_permutation()
{
    std::string permutation = ALPHABET;
    std::random_shuffle(permutation.begin(), permutation.end());
    return permutation;
}
int main(){
    srand(time(NULL)); // caveat: time's minimum resolution is 1 second.
                       // multiple executions of this program within 1
                       // second will get the same time and use the same seed.
    std::cout << create_permutation() << std::endl;
    std::cout << create_permutation() << std::endl;
    std::cout << create_permutation() << std::endl;
    std::cout << create_permutation() << std::endl;
    std::cout << create_permutation() << std::endl;
    return 0;
}

一种更现代的方法:

#include <random>
#include <algorithm>
#include <iostream>
#include<string>
const std::string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,' ";
std::random_device rd; // Warning: implementation of this is allowed to be stupid and 
                       // return the same value every time. Does not work in mingw 4.8
                       // Can't speak for 4.9 or greater
std::mt19937 randomizer(rd());

std::string create_permutation()
{
    std::string permutation = ALPHABET;
    std::shuffle(permutation.begin(), permutation.end(), randomizer);
    return permutation;
}

int main()
{
    std::cout << create_permutation() << std::endl;
    std::cout << create_permutation() << std::endl;
    std::cout << create_permutation() << std::endl;
    std::cout << create_permutation() << std::endl;
    std::cout << create_permutation() << std::endl;
}