Evgenii Legotckoi
Evgenii LegotckoiDec. 14, 2017, 5:10 p.m.

Qt/C++ - Tutorial 074. Generating pseudo-random numbers, using STD library random

Generating random numbers may be needed, for example, to calculate weapon damage in a computer game or to represent a graph from random numbers.

Qt provides the qrand function for generating random numbers, and also, starting with Qt 5.10 , the QRandomGenerator class.

Let's see how random values can be obtained in Qt, and how random they are.


qrand

We will generate numbers in the range of values from and to. For this we write two functions.

static int randomBetween(int low, int high)
{
    return (qrand() % ((high + 1) - low) + low);
}

static int randomBetween(int low, int high, int seed)
{
    qsrand(seed); // Setting a base number for counting a random in qrand
    return (qrand() % ((high + 1) - low) + low);
}

The first function simply generates a random value from the smallest number to the largest. Whereas in the second, using the qsrand function, the base number is set, which serves as the basis for the pseudo-random number generator Qt, from which the number is generated. This base number can be the system time in milliseconds.

We apply these functions.

#include <QCoreApplication>
#include <QDateTime>
#include <iostream>

static int randomBetween(int low, int high)
{
    return (qrand() % ((high + 1) - low) + low);
}

static int randomBetween(int low, int high, int seed)
{
    qsrand(seed); // Setting the base number for counting a random host in qrand
    return (qrand() % ((high + 1) - low) + low);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::cout << "Random Qt 1 - ";
    for (int i = 0; i < 15; ++i)
    {
        std::cout << randomBetween(15, 43) << " ";
    }
    std::cout << std::endl;

    std::cout << "Random Qt 2 - ";
    for (int i = 0; i < 15; ++i)
    {
        std::cout << randomBetween(15, 43, QDateTime::currentMSecsSinceEpoch()) << " ";
    }
    std::cout << std::endl;

    return a.exec();
}

We obtain the following conclusion.

Random Qt 1 - 15 21 31 27 17 34 43 33 22 32 30 34 35 38 31 
Random Qt 2 - 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 

And now we analyze the resulting conclusion.

In the first case, the numbers turned out random ... But how much? If you try to run the program several times in a row, you will see that the numbers will be the same each time, which is not very good and obviously not very randomly.

As for the second option, here all the numbers turned out to be the same. The fact is that each time we tried to set the base number as the same number. Indeed, a processor with a frequency of a couple of GHz will very quickly execute that simple cycle, and therefore time in milliseconds simply will not have time to change, and therefore the base number will be the same. And when you set the base number, the generation will be done from the very beginning and in this case you will see that it is not very random.

And now let's see what we were offered in Qt 5.10

QRandomGenerator

The QRandomGenerator application will be next

#include <QCoreApplication>
#include <iostream>

#include <QRandomGenerator>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::cout << "Random Qt 3 - ";
    QRandomGenerator generator;
    for (int i = 0; i < 15; ++i)
    {
        qint64 value = generator.generate() & std::numeric_limits<qint64>::max();
        std::cout << value << " ";
    }
    std::cout << std::endl;

    return a.exec();
}

The output will be as follows

Random Qt 3 - 853323747 2396352728 3025954838 2985633182 2815751046 340588426 3587208406 298087538 2912478009 3642122814 3202916223 799257577 1872145992 639469699 3201121432

In fact, the same problem will repeat here as with qrand, when you repeatedly start the program, you will see the numbers will be repeated. In the news about the Qt 5.10 release, this class is said to function better than the normal qrand, but in fact the problem remains the same. Perhaps with longer testing within the program, which constantly uses the generation of random numbers, you can see significant differences, but in the framework of even such a simple version, there are already shortcomings.

What to do?

In trying to find an acceptable solution for generating random numbers for a single project, I was able to find information that there is a random library in the STD Library for the C ++ 11 standard, in which there is a more acceptable option for generating random numbers. The implementation of one very interesting library was found on the Git Hub. Based on that library, I wrote a small class to generate (read between the lines, a little rewritten for myself to figure it out).

Random.hpp

The class that is implemented here uses Myers' singleton to do static methods of obtaining random values in a certain range. It is much easier to call one static class method in the right place than to initialize all the random number generators each time. The class itself works both as integer types and as floating point types.

#ifndef RANDOM_HPP
#define RANDOM_HPP

#include <random>

namespace details
{
    /// True if type T is applicable by a std::uniform_int_distribution
    template<class T>
    struct is_uniform_int {
        static constexpr bool value =
                std::is_same<T,              short>::value ||
                std::is_same<T,                int>::value ||
                std::is_same<T,               long>::value ||
                std::is_same<T,          long long>::value ||
                std::is_same<T,     unsigned short>::value ||
                std::is_same<T,       unsigned int>::value ||
                std::is_same<T,      unsigned long>::value ||
                std::is_same<T, unsigned long long>::value;
    };

    /// True if type T is applicable by a std::uniform_real_distribution
    template<class T>
    struct is_uniform_real {
        static constexpr bool value =
                std::is_same<T,       float>::value ||
                std::is_same<T,      double>::value ||
                std::is_same<T, long double>::value;
    };
}

class Random
{
    template <class T> using IntDist = std::uniform_int_distribution<T>;
    template <class T> using RealDist = std::uniform_real_distribution<T>;

public:
    template <class T>
    static typename std::enable_if<details::is_uniform_int<T>::value, T>::type get(T from = std::numeric_limits<T>::min(), T to = std::numeric_limits<T>::max())
    {
        if (from > to) std::swap(from, to);
        IntDist<T> dist{from, to};
        return dist(instance().engine());
    }

    template <class T>
    static typename std::enable_if<details::is_uniform_real<T>::value, T>::type get(T from = std::numeric_limits<T>::min(), T to = std::numeric_limits<T>::max())
    {
        if (from > to) std::swap(from, to);
        RealDist<T> dist{from, to};
        return dist(instance().engine());
    }

    std::mt19937& engine() { return m_mt; }

protected:
    static Random& instance()
    {
        static Random inst;
        return inst;
    }

private:
    std::random_device m_rd; // Random Number Generator
    std::mt19937 m_mt;       // Standard random number generator

    Random() : m_mt(m_rd()) {}
    ~Random() {}
    Random(const Random&) = delete;
    Random& operator = (const Random&) = delete;
};

#endif // RANDOM_HPP

main.cpp

And now the application

#include <QCoreApplication>

#include "Random.hpp"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::cout << "Random STD  - ";
    for (int i = 0; i < 15; ++i)
    {
        std::cout << Random::get(15, 43) << " ";
    }
    std::cout << std::endl;
    return a.exec();
}

Output

Random STD  - 38 29 36 38 21 32 33 39 31 15 33 16 36 38 35 

In this case, we will actually get a random output of numbers, and the numbers will not be repeated every time the program is run. As for randomness, I was convinced of this personally, when I used the given Random class to generate a level in the game. Each time the arrangement of objects in the game was not repeated. What was very difficult to achieve with qrand.

So C++11 provides possiblities to allocate qualitative enough generation of pseudo-random numbers.

And here is the link to the library from GitHub , on which I studied this issue.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

Дмитрий
  • Oct. 29, 2020, 9:37 a.m.
  • (edited)

А использование функции global() не решает ли эти проблемы?

value = QRandomGenerator::global()->bounded(15, 43);

Получаемая последовательность каждый раз новая.

r
  • Jan. 17, 2021, 4:09 a.m.

Дмитрий, решает. Просто автор, видимо, не сильно озаботился изучением документации QRandomGenerator.
Да и в листинге с использованием qrand вызов функции qsrand на каждой итерации цикла наводит на мысль, что автор, мягко говоря, не очень понимает для чего это всё нужно.

Comments

Only authorized users can post comments.
Please, Log in or Sign up
e
  • ehot
  • April 1, 2024, 2:29 a.m.

C++ - Тест 003. Условия и циклы

  • Result:78points,
  • Rating points2
B

C++ - Test 002. Constants

  • Result:16points,
  • Rating points-10
B

C++ - Test 001. The first program and data types

  • Result:46points,
  • Rating points-6
Last comments
k
kmssrFeb. 9, 2024, 7:43 a.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVADec. 25, 2023, 11:30 p.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJoDec. 25, 2023, 9:38 p.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
GvozdikDec. 19, 2023, 10:01 a.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
G
GarApril 22, 2024, 5:46 p.m.
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil AcademicsApril 20, 2024, 7:45 p.m.
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasovApril 14, 2024, 6:41 p.m.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел ДорофеевApril 14, 2024, 2:35 p.m.
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrexApril 4, 2024, 4:47 p.m.
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Follow us in social networks