muzruno.com

Функция Случайна C ++

В разгара на създаване STL и насилие война за стандартен номер C ++ език от програмисти са разработили свой собствен клас междуплатформена библиотека предоставя на разработчиците инструменти, за да се справят с ежедневните задачи, като например за обработка на данни, алгоритми и работа с файлове и така нататък. D. Тази библиотека се нарича Boost. Проектът е толкова успешен, че стимулира възможност назаем и се вписват в стандартния език, тъй като C ++ 11. Едно от тези допълнения е подобрената работа с произволни числа.

Псевдо-случаен генератор

Функциите rand () и srand () се отнасят до нивото на училището и са подходящи за писане на прости програми. Недостатъкът на тези функции е генерирането на недостатъчно добра поредица от псевдо-случайни номера (картинката по-горе). Също така, възможностите за прости функции не са достатъчни при разработването на сложни проекти.

За решаването на проблема бяха създадени генератори на произволни числа (наричани по-долу "RNG"). С техния външен вид, работата по генерирането на много видове данни, псевдо-и наистина случайни, е значително подобрена. Пример за генерирането на истински произволни номера е шума на снимката по-долу.

Наистина произволен генератор

Генератор на псевдо-случаен номер

Зарчета като символ на случайността

Традиционният алгоритъм за създаване на MF комбинира алгоритъма за създаване на непредсказуеми бита и превръщането им в поредица от числа. В случайната C ++ библиотека, която е част от Boost, тези два механизма са разделени. Сега генерирането на произволни числа и тяхното създаване (последователност) става отделно. Използването на разпространението е напълно логично. Тъй като произволен номер без определен контекст няма смисъл и е трудно да се използва. Нека да напишем проста функция, която хвърля кокал:

#include int roll_a_dice () {std :: default_random_engine e {} - // create randomness generatorstd :: uniform_int_distribution	d {1, 6} // създаване на разпределение с минимални и максимални стойности връщане d (e) -}

Често срещана грешка за тези, които учат на случаен принцип, е да пренебрегнат създаването на разпространението и да се насочат направо към създаването на произволни числа в начина, по който са свикнали. Например разгледайте описаната по-горе функция.

връщане 1 + e ()% 6-

Някои смятат, че подобна употреба е приемлива. C ++ ви позволява да работите по този начин. Въпреки това, създателите на библиотеката "Boost" и стандартите C ++ 11 са силно посъветвани да не правят това. В най-добрия случай това ще бъде само лош код и в най-лошия случай ще бъде работен код, който прави грешки, които са много трудни за улов. Използването на дистрибуции гарантира, че програмистът получава това, което очаква.

Инициализация на генератора и семена

Етапът на деклариране, дефиниране и създаване на обекти често се разглежда като нещо, което не се нуждае от специално внимание. Но не достатъчно обмислена инициализация на генератора на произволни числа може да повлияе на правилната му работа.

std :: default_random_engine e1- // имплицитна инициализация по подразбиранеstd :: default_random_engine e2 {} - // изрична инициализация с стойността по подразбиране

Първите две инициализации са еквивалентни. И в по-голямата си част те се отнасят до вкуса или стандартите за писане на красив код. Но следната инициализация е коренно различна.

std :: default_random_engine e3 {31255} - // Инициализация със стойност 31255

"31255" - това се нарича семена (семе, източник) - числото, въз основа на което генераторът създава произволни числа. Ключовият момент тук е, че при тази инициализация типа на семето трябва да бъде същият или типа, с който работи генераторът. Този тип е достъпен чрез конструкцията на decltype (e ()), или result_of, или име на типа.

Защо генераторът създава същите последователности?

Когато програмата се изпълнява няколко пъти, генераторът винаги създава същата последователност от номера, ако неговата инициализация не се променя, т.е. дефиницията на генератора се извършва по същия начин, започвайки от стартирането на програмата. От една страна, това саморепродукция на числата от генератора е полезно например при отстраняване на грешки. И от друга - е нежелателно и може да създаде проблеми.

Съответно, за да се избегне повтарянето на последователността от номера, генераторът трябва да се инициализира с различни стойности всеки път, когато програмата стартира. Само за тези цели можете да използвате семена. Стандартният начин да се инициализира GPRS е да се изпрати като време за семена (0) от файла на заглавния файл. Това означава, че генераторът ще бъде инициализиран със стойност, равна на броя изминали секунди от 1 00 00 00 минути 00 секунди, 1970 г. от UTC.

Инициализиране на GPRS с друг генератор

Инициализирането на време може да не е достатъчно, за да разрешите редица задачи. След това е възможно да се определи GPRS чрез друг генератор. Тук бих искал да направя отклонение и да говоря за един мощен инструмент, който ви позволява да създавате истински произволни номера.

Random_device - генератор на наистина случайни номера

Случайни числа

Всички генератори на псевдо-произволни числа са детерминирани. Това означава, че те имат определение. Или с други думи получаването на произволни числа се основава на математически алгоритми. Random_device също е недеterministic. Той създава числа въз основа на стохастични (произволни с гръцко-гръцки) процеси. Такива процеси могат да бъдат промени във фазата или амплитудата на текущите колебания, колебанията в молекулните решетки, движението на въздушните маси в атмосферата и т.н.

Очевидно не всеки компютър и всяка система може да има вградена способност да получи произволен номер въз основа на стохастичен процес. Поради това трябва да прибягвате до използването на произволно решение само ако е необходимо. Работата му може да се различава от система на система, от компютър до компютър и може дори да е недостъпна. Следователно, когато се използва генератор с наистина случайни числа, е необходимо да се осигури обработка на грешки.

Използване на random_device като семе за RAND

std :: random_device rd {} - std :: default_random_engine е {rd ()} -


В този кодекс няма нищо ново. В същото време, при всяко стартиране, GISCH се инициализира с случайни стойности, генерирани от генератора на наистина случайни числа rd.

Заслужава да се отбележи, че инициализиращата стойност на генератора може да бъде нулирана по всяко време:

e.seed (15027) // инициализира number.seed () - // инициализира с стойност default.seed (rd ()) - // инициализира с друг генератор

Общи: генератори и дистрибуции

Двигателят е обект, който ви позволява да създавате различни еквивалентни номера.

Разпределението (distirbution) е обект, който преобразува последователността от числа, създадени от генератора, в разпределения съгласно даден закон, например:

  • единна (еднакво);
  • Нормално - Гаусово (нормално);
  • биноми и т.н.

Помислете за генераторите на стандартната библиотека C ++.

  1. Достатъчно е за начинаещите да използват default_random_engine, оставяйки генератора да избере библиотеката. Генераторът ще бъде избран въз основа на комбинация от фактори като производителност, размер, качество на случайността.
  2. За опитни потребители библиотеката предоставя 9 предварително зададени генератора. Те са много различни по отношение на производителността и размера, но в същото време качеството им на работа е подложено на сериозни тестове. Често се използва генератор, наречен Mersenne twister, и неговите мостри mt19937 (създаване на 32-битови номера) и mt19937_64 (създаване на 64-битови номера). Генераторът е оптимална комбинация от скорост и случайност. За повечето от проблемите, които възникват, ще бъде достатъчно.
  3. За експертите библиотеката предоставя конфигурирани шаблони за генератори, които позволяват създаването на допълнителни видове генератори.
Нормално разпределение

Нека разгледаме ключовите аспекти на разпределението. На стандартния език има 20 от тях. В горния пример се използва произволно разпределение на случайната C ++ библиотека в диапазона [a, b] за числа - uniform_int_distribution. Може да се използва същото разпределение реални номера: uniform_real_distribution със същите параметри a и b на интервала за генериране на числа. Освен това границите на интервала са включени, т.е. [a, b]. Да изброите всичките 20 разпределения и да повторите документацията на C ++ в статията няма смисъл.

Трябва да се отбележи, че всяко разпределение има свой набор от параметри. За равномерно разпределение това е интервалът от a до b. И за геометричен (geometric_distribution) параметър, вероятността за успех е p.

Повечето от разпределенията се дефинират като шаблон на класа, за който параметърът е тип на стойностите на последователността. Някои дистрибуции обаче създават само последователности за стойности на int или само реални стойности. Или, например, последователността Bernoulli (bernoulli_distribution), която осигурява стойности като bool. Както при RNG, потребителят на библиотеката може да създава свои собствени дистрибуции и да ги използва с вградени генератори или генератори, които ще създадат.

Гама разпределение

Възможностите на библиотеката не са ограничени до това. Те са много по-широки. Но предоставената информация е достатъчна за използването и основното разбиране на генератора на случаен номер в C ++.

Кратка информация: Случайна в стила на .Net

Рамката .Net също има Random клас за създаване на псевдо-случайни номера. Да разгледаме пример за генериране Случаен номер С ++ / CLI.

За тези, които работят в Visual Studio и не могат да разберат защо не е дефинирано пространственото пространство на системата.

За да работите с .net, трябва да свържете CLR. Това се прави с две sposobami.1) Създаване на проект не е прозорци конзола приложение, и с подкрепата на CLR - Конзола приложение CLR (CLR Console Application) 0.2) Свържете подкрепата на CLR в настройките вече създаден проект: свойства на проекта (на "проект", а не " ) -> конфигурация -> общи -> стойности по подразбиране -> изберете "Поддръжка на CLR (/ clr)" в падащия списък на поддръжката "Обща езикова модулация (CLR)".

#include "stdafx.h" #include // използване именно пространство Системни-Int основни (масив ^ опцията) {Система :: Произволни ^ Rnd1 = gcnew система :: Random () - // създаване RNG подразбиране инициализира ток vremenemstd :: Cout << rnd1-> Напред () << " n" - // връща положително цяло число int горно = 50-std :: cout << rnd1-> Next (горна) << " n" - // връща положително цяло число не по-голямо от upperint a = -1000- int b = -500-std :: cout << rnd1-> Next (a, b) << " n" - // връща цялото число в диапазона [a, b] int seed = 13977-System :: Random ^ rnd2 = gcnew System :: Random (seed) - // initialize RNG с числото seedstd :: cout << rnd2-> Next (500, 1000) << " n" - // при всяко стартиране на програмата ще се създаде същото число std :: cout << std :: endl-return 0-}

В този случай цялата работа се извършва благодарение на функцията Random Next C ++ / CLI.

Струва си да се отбележи, че .net е голяма библиотека с обширни възможности и използва собствена версия на езика, наречен C ++ / CLI от Common Language Infrastructure. По принцип това е разширение на C ++ за платформата .Net.

В края на краищата разгледайте няколко примера, за да разберете по-добре работата с произволни номера.

#include #include #include int main () {std :: mt19937 e1-e1.seed (време (0)) - std :: cout << e1 () << std :: endl-std :: mt19937 e2 (време (0)) - std :: mt19937 e3 {} - std :: uniform_int_distribution uid1 (5, 10), uid2 (1, 6) -std :: cout << uid1 (e2) << "," << uid2 (е3) << std :: endl-std :: default_random_engine e4 {} - std :: uniform_real_distribution urd (0.5, 1.2) -std :: normal_distribution nd (5.0, 2.0) - // нормално разпределение със средна стойност 5.0 и стандартно отклонение 2.0std :: cout << urd (е4) << "," << nd (e4) << std :: endl-std :: cout << std :: endl-system ("пауза") - връщане 0-}

заключение

Всяка технология и методи непрекъснато се развиват и подобряват. Така се случи с механизма за генериране на произволни номера rand (), който е остарял и не отговаря на съвременните изисквания. В STL има произволна библиотека, в .Net Framework, класа Random за работа с произволни номера. От използвайки ред Необходимо е да се откажем в полза на нови методи, тъй като те съответстват на съвременните програмни парадигми и старите методи ще бъдат извлечени от стандарта.

Споделяне в социалните мрежи:

сроден