Evgenii Legotckoi
Evgenii LegotckoiЖел. 14, 2017, 5:10 Т.Қ.

Qt/C++ - 074-сабақ. Кездейсоқ STD кітапханасын пайдаланып жалған кездейсоқ сандарды құру

Кездейсоқ сандарды генерациялау, мысалы, компьютерлік ойында қарудың зақымдалуын есептеу немесе кездейсоқ сандар графигін көрсету үшін қажет болуы мүмкін.

Qt кездейсоқ сандарды генерациялау үшін qrand функциясын қамтамасыз етеді және Qt 5.10 бастап QRandomGenerator класы.

Qt-де кездейсоқ мәндерді қалай алуға болатынын және олардың қаншалықты кездейсоқ екенін көрейік.


үлкен

Біз бастап және дейін мәндер ауқымында сандарды жасаймыз. Ол үшін екі функция жазамыз.

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);
}

Бірінші функция ең кіші саннан ең үлкеніне дейін кездейсоқ мәнді жасайды. Ал екіншісінде, qsrand функциясын пайдалана отырып, базалық сан орнатылады, ол сан жасалатын Qt жалған кездейсоқ сандар генераторы үшін негіз болады. Бұл негізгі сан жүйе уақыты миллисекундтар болуы мүмкін.

Осы функцияларды қолданайық.

#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();
}

Біз келесі нәтижені аламыз.

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 

Енді алынған нәтижені талдап көрейік.

Бірінші жағдайда сандар кездейсоқ болып шықты... Ал қанша? Бағдарламаны қатарынан бірнеше рет іске қосуға тырыссаңыз, сандар әр уақытта бірдей болатынын көресіз, бұл өте жақсы емес және өте кездейсоқ емес.

Екінші нұсқаға келетін болсақ, мұнда барлық сандар бірдей болып шықты. Мәселе мынада, біз әр уақытта негізгі нөмірді бірдей сан етіп орнатуға тырыстық. Ақыр соңында, екі ГГц жиілігі бар процессор бұл қарапайым циклды өте жылдам орындайды, яғни миллисекундтардағы уақыт өзгеруге уақыт болмайды, яғни базалық нөмір бірдей болады. Ал негізгі нөмірді орнатқан кезде генерация ең басынан орындалады, бұл жағдайда оның өте кездейсоқ емес екенін көресіз.

Енді Qt [5.10] ішінде бізге не ұсынылғанын көрейік (https://evileg.com/post/312/)

QRandomGenerator

QRandomGenerator қолданбасы келесідей болады

#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();
}

Шығару келесідей болады

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

Шындығында, qrand-пен бірдей мәселе осы жерде қайталанады, бағдарламаны қайта іске қосқанда, сандар қайталанатынын көресіз. Qt 5.10 шығарылымының жаңалықтары бұл сынып қалыпты qrand-қа қарағанда жақсы жұмыс істейтінін айтады, бірақ іс жүзінде мәселе сол күйінде қалады. Мүмкін, кездейсоқ сандарды генерациялауды үнемі қолданатын бағдарламаның ішінде ұзағырақ тестілеу кезінде сіз айтарлықтай айырмашылықтарды көре аласыз, бірақ мұндай қарапайым нұсқаның өзінде кемшіліктер бар.

Не істеу?

Бір жоба үшін кездейсоқ сандарды генерациялаудың қолайлы шешімін табуға тырысып, мен кездейсоқ сандарды генерациялаудың қолайлы нұсқасы бар C ++ 11 стандарты үшін STD кітапханасында кездейсоқ кітапхана бар екендігі туралы ақпаратты таба алдым. Git Hub сайтында өте қызықты бір кітапхананың іске асырылуы табылды. Осы кітапхананы негізге ала отырып, мен ұрпаққа шағын сынып жаздым (жолдардың арасын оқыңыз, өзім түсіну үшін аздап қайта жаздым).

Random.hpp

Мұнда енгізілген класс белгілі бір ауқымда кездейсоқ мәндерді алу үшін статикалық әдістерді орындау үшін Myers синглтонын пайдаланады. Кездейсоқ сандар генераторларының барлығын инициализациялаудан гөрі бір статикалық класс әдісін дұрыс жерде шақыру әлдеқайда оңай. Сыныптың өзі бүтін сан түрлерімен де, өзгермелі нүкте түрлерімен де жұмыс істейді.

#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

Ал енді қолданба

#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();
}

Қорытынды

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

Бұл жағдайда біз сандардың кездейсоқ шығарылымын аламыз және бағдарлама іске қосылған сайын сандар қайталанбайды. Кездейсоқтыққа келетін болсақ, мен ойында деңгейді құру үшін осы Random класын пайдаланған кезде бұған жеке көзім жетті. Әр жолы ойындағы заттардың орналасуы қайталанбады. Бұған qrand арқылы жету өте қиын болды.

Сонымен, C++11 псевдокездейсоқ сандарды жеткілікті жоғары сапалы генерациялауға мүмкіндік береді.

Міне, мен бұл мәселені зерттеген GitHub кітапханасынан сілтеме .

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

Дмитрий
  • Қаз. 29, 2020, 9:37 Т.Ж.
  • (өңделген)

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

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

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

r
  • Қаң. 17, 2021, 4:09 Т.Ж.

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

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 6:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 25, 2024, 1 Т.Ж.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 5:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

Бізді әлеуметтік желілерде бақылаңыз