Qt 工具类(01):随机数QRandomGenerator类

一、前言

QRandomGenerator类允许从高质量随机数生成器获取随机值。
 Header : #include < QRandomGenerator >
 qmake : QT += core
 Since : Qt 5.10
 Inherited By : QRandomGenerator64

二、详述

QRandomGenerator可用于从高质量随机数生成器生成随机值。像C++随机引擎一样,QRandomGenerator可以通过构造函数以用户提供的值作为种子。播种后,此类生成的数字序列是确定性的。也就是说,给定相同的种子数据,QRandomGenerator将生成相同的数字序列。但是给定不同的种子,结果应该有很大的不同。

QRandomGenerator :: securelySeeded()可用于创建QRandomGenerator,并使用QRandomGenerator :: system()安全地植入该种子,这意味着无法轻松预测其生成的数字序列。此外,QRandomGenerator :: global()返回QRandomGenerator的全局实例,Qt将确保该实例被安全地播种。该对象是线程安全的,可以为大多数使用共享,并且始终从QRandomGenerator :: system()得到种子。

QRandomGenerator :: system()可用于访问系统的密码安全随机生成器。在Unix系统上,这等效于从/ dev / urandom或getrandom()或getentropy()系统调用中读取。

类可以生成32位或64位数量,或填充数组。生成新值的最常见方法是调用generate(),generate64()或fillRange()函数。可以将其用作:

quint32 value = QRandomGenerator::global()->generate();

外,它还提供了一个浮点函数generateDouble(),该函数返回一个范围为[0,1)的数字(即不包括0,不包括1),还有一组方便函数,可以方便地获取一个有界的整数范围内的随机数。

1、播种和确定性

QRandomGenerator可以使用特定的种子数据进行播种。 完成后,对象生成的数字将始终相同,如以下示例所示:

     QRandomGenerator prng1(1234), prng2(1234);
     Q_ASSERT(prng1.generate() == prng2.generate());
     Q_ASSERT(prng1.generate64() == prng2.generate64());

子数据采用一个或多个32位字的形式。 理想的种子大小大约等于QRandomGenerator类本身的大小。 由于混合了种子数据,QRandomGenerator无法保证不同的种子将产生不同的序列。

QRandomGenerator::securelySeeded()创建的所有生成器一样,QRandomGenerator :: global()总是从QRandomGenerator :: system()播种,因此不可能使其产生相同的序列。

2、批量数据

确定性模式下运行时,QRandomGenerator可用于批量数据生成。 实际上,建议不需要密码安全或真实随机数据的应用程序使用常规QRandomGenerator代替QRandomGenerator :: system() 满足其随机数据需求。

了易于使用,QRandomGenerator提供了一个易于使用的全局对象,如以下示例所示:

     int x = QRandomGenerator::global()->generate();
     int y = QRandomGenerator::global()->generate();
     int w = QRandomGenerator::global()->bounded(16384);
     int h = QRandomGenerator::global()->bounded(16384); 

3、系统范围内的随机数生成器

QRandomGenerator :: system() 可用于访问系统范围的随机数生成器,该生成器在运行Qt的所有系统上都是加密安全的。此功能将使用硬件工具生成可用的随机数。在这样的系统上,那些工具是真正的随机数生成器。但是,如果它们是真正的RNG,则这些设施的熵源有限,因此如果耗尽其熵池,可能无法产生任何结果。

果发生这种情况,首先操作系统,然后是QRandomGenerator会退回到质量降低的伪随机数生成器(Qt的后备生成器是最简单的)。那些生成器是否仍具有加密质量是实现定义的。因此,QRandomGenerator :: system() 不应用于高频随机数生成,以免熵池变空。根据经验,不应调用此类来生成每秒超过一千字节的随机数据(注意:这可能因系统而异)。

果应用程序需要大量的真实RNG数据,则应直接使用操作系统工具(例如Linux上的/ dev / random)并等待熵变为可用。如果应用程序需要具有加密质量但不是真正随机性的PRNG引擎,则仍可以使用QRandomGenerator :: system() (请参阅以下部分)。

果既不需要真正的RNG,也不需要加密安全的PRNG,则应用程序应改用PRNG引擎,例如QRandomGenerator的确定性模式和C++标准库中的那些。 QRandomGenerator :: system() 可用于为这些播种。

4、后备质量

QRandomGenerator :: system() 使用操作系统工具来获取随机数,该随机数试图从周围环境中收集真实的熵以产生真实的随机数。但是,熵池有可能耗尽,在这种情况下,操作系统将暂时退回到伪随机引擎。在任何情况下,QRandomGenerator :: system() 都不会阻塞,等待收集更多的熵。

下操作系统保证即使熵池用尽,其随机生成的API的结果也至少具有加密安全的质量:Apple OS(Darwin),BSD,Linux,Windows。除非存在系统安装问题(例如/ dev / urandom无法被当前进程读取),否则QRandomGenerator :: system() 将具有相同的保证。

其他操作系统上,QRandomGenerator将退回到具有良好数字分布的PRNG,但是它不能保证在所有情况下都可以正确播种。请查阅操作系统文档以获取更多信息。

议要求QRandomGenerator不退回非加密质量生成器的应用程序检查其操作系统文档或将其部署限制为上述之一。

5、可重入和线程安全

QRandomGenerator是可重入的,这意味着多个线程可以同时在该类上运行,只要它们在不同的对象上运行即可。 如果多个线程需要共享一个PRNG序列,则需要使用互斥锁进行外部锁定。

QRandomGenerator :: global() 和QRandomGenerator :: system() 返回的对象是例外:这些对象是线程安全的,任何线程都可以使用而无需外部锁定。 请注意,线程安全性并不限于复制那些对象:它们应始终通过引用使用。

6、标准C++库兼容性

QRandomGenerator是根据C++标准库中对随机数引擎的要求建模的,并且可以在标准库引擎可以使用的几乎所有上下文中使用。 要求的例外情况如下:

  • QRandomGenerator除了std :: seed_seq本身之外,不支持从另一个类似于种子序列的类进行播种;

  • QRandomGenerator与std :: ostream或std :: istream不具有可比性(但可复制)或可流式传输。

QRandomGenerator也与统一分发类std :: uniform_int_distribution和std:uniform_real_distribution以及自由函数std :: generate_canonical兼容。 例如,以下代码可用于生成范围为[1,2.5)的浮点数:

     std::uniform_real_distribution dist(1, 2.5);
     return dist(*QRandomGenerator::global());

请参见QRandomGenerator 64和grand() 。

三、公共类型

  1. typedef result_type

    typedef quint32 result_type;
    

    对operator() 返回的类型的typedef。 也就是说,quint32。

四、公共函数

  1. 构造函数
    QRandomGenerator(const QRandomGenerator &other)
    QRandomGenerator(const quint32 *begin, const quint32 *end)
    QRandomGenerator(std::seed_seq &sseq)
    QRandomGenerator(const quint32 *seedBuffer, qsizetype len)
    QRandomGenerator(const quint32 (&)[N] seedBuffer = N)
    QRandomGenerator(quint32 seedValue = 1)

  2. double bounded(double highest)

    在0(含)和 highest(不含)之间生成一个随机的double。 此功能等效于并实现为:
    return generateDouble() * highest;
    如果最高参数为负,则结果也将为负。 如果它是无穷大或NaN,则结果也将是无穷大或NaN(即不是随机的)。

  3. quint32 bounded(quint32 highest)

    生成[0,hightest) 范围内的quint32 类型的整数

  4. quint32 bounded(quint32 lowest, quint32 highest)

    生成[lowest,hightest) 范围内的quint32 类型的整数

  5. int bounded(int highest)

    生成[0,hightest) 范围内的int类型的整数

  6. int bounded(int lowest, int highest)

    生成[lowest,hightest) 范围内的int类型的整数

  7. void discard(unsigned long long z)

    丢弃序列中的下z个条目。 此方法等效于z调用generate() 并丢弃结果,如下所示:

         while (z--)
             generator.generate();
    
  8. void fillRange(UInt *buffer, qsizetype count)

    生成32或64位计数(取决于UInt类型),并将其存储在buffer指向的缓冲区中。 这是一次获取多个数量的最有效方法,因为它减少了进入随机数生成器源的调用次数。

  9. void fillRange(UInt (&)[N] buffer = N)

    比如:

         quint32 array[2];
         QRandomGenerator::fillRange(array);
    
  10. quint64 generate64()

    生成64位的随机值

  11. quint32 generate()

    生成32位的随机值

  12. void generate(ForwardIterator begin, ForwardIterator end)

    生成32位数量并将其存储在开始和结束之间的范围内。如果范围是指连续内存(例如数组或QVector中的数据),则也可以使用fillRange() 函数。

  13. double generateDouble()

    生成一个在规范范围[0,1)中的随机qreal(即,包含零且不包含1)。

  14. void seed(quint32 seed = 1)

    使用值种子作为种子来重新播种此对象。

  15. void seed(std::seed_seq &seed)

    使用种子序列种子作为种子来播种此对象。

  16. QRandomGenerator::result_type operator()()

    生成一个32位随机数并将其返回。操作符重载函数。

五、静态公用函数

  1. QRandomGenerator * global()

    回一个指向共享的QRandomGenerator的指针,该指针使用securelySeeded() 作为种子。 此函数应用于创建随机数据,而无需为特定用途或为存储相当大的QRandomGenerator对象而昂贵地创建安全播种的QRandomGenerator。

    如,以下创建随机的RGB颜色:
    return QColor::fromRgb(QRandomGenerator::global()->generate());

    该对象的访问是线程安全的,因此可以在没有锁的任何线程中使用它。 该对象也可以被复制,并且复制所产生的顺序将与共享对象所产生的顺序相同。 但是请注意,如果还有其他线程正在访问全局对象,则这些线程可能会以不可预测的时间间隔获取样本。

    意:此函数是线程安全的。

  2. QRandomGenerator::result_type max()

    返回QRandomGenerator可能生成的最大值。 也就是说,std :: numeric_limits <结果类型> :: max() 。

  3. QRandomGenerator::result_type min()

    返回QRandomGenerator可能生成的最小值。 即0。

  4. QRandomGenerator securelySeeded()

    回一个新的QRandomGenerator对象,该对象已通过QRandomGenerator :: system() 安全地植入。 该函数将为QRandomGenerator使用的算法获得理想的种子大小,因此是创建新的QRandomGenerator对象并将其保留一段时间的推荐方法。

    虑到安全播种确定性引擎所需的数据量,此功能有些昂贵,不应用于QRandomGenerator的短期使用(使用它生成少于2600字节的随机数据实际上是对资源的浪费)。 如果使用不需要大量数据,请考虑使用QRandomGenerator :: global() ,而不要存储QRandomGenerator对象。

  5. QRandomGenerator * system()

    回一个指向共享QRandomGenerator的指针,该指针始终使用操作系统提供的功能来生成随机数。 至少在以下操作系统上,系统设施被认为具有加密安全性:Apple操作系统(Darwin),BSD,Linux,Windows。 在其他操作系统上也可能是这种情况。

    们也可能由真正的硬件随机数生成器支持。 因此,此函数返回的QRandomGenerator不应用于批量数据生成。 而是使用它为QRandomGenerator或标头中的随机引擎提供种子。

    函数返回的对象是线程安全的,可以在没有锁的任何线程中使用。 也可以将其复制,并且生成的QRandomGenerator也将访问操作系统工具,但它们不会生成相同的序列。

六、有关系的非成员函数

bool operator!=(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)

七、示例

#include <QCoreApplication>
#include <QRandomGenerator>
#include <QDebug>
#include <QTime>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QRandomGenerator rng(QTime::currentTime().msecsSinceStartOfDay());

    unsigned int arr[10];
    rng.fillRange(arr,10);

    for (int i = 0; i < 10; ++i) {
        qDebug("%10u",arr[i]);
    }

    qDebug()<<"---------------";

    rng.fillRange(arr,10);
    for (int i = 0; i < 10; ++i) {
        qDebug("%10u",arr[i]);
    }
    return a.exec();
}

八、总结

QRandomGenerator 常在随机试验是使用,生成测试数据时,或者生成随机颜色等。不过庆幸的是,使用方法十分简单。

QRandomGenerator64则是QRandomGenerator的简单适配器类,旨在生成64位而不是32位的数值。只有一个generate()函数。

  • 14
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值