Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Общие вопросы _ рандом

Автор: eldar85 15.7.2010, 15:36

пользуюсь рандомом такого вида

qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()));
   int rand = qrand()%9000+1000;

но если его запускать в цикле то получается слишком много повторов одного и того же числа, так как он генерит новое число со следующей секунды... нет ли способа усовершенствовать как то этот подход чтобы повторы были минимальны? кто нить пользовался такой штукой?

Автор: igor_bogomolov 15.7.2010, 15:41

Так ты qsrand(QTime(0,0,0).msecsTo(QTime::currentTime())); вынеси за тело цикла

Автор: eldar85 15.7.2010, 15:44

хмм, точно))) благодарю)

Автор: Litkevich Yuriy 15.7.2010, 18:54

eldar85, srand - инициализирует генератор (с чего начинать), а сам генератор - rand

Автор: DEADHUNT 15.7.2010, 20:51

зачем использовать какие-то непонятные Qt конструкции, всё гораздо проще:

#include <cstdlib>
#include <ctime>
std::srand(std::time(NULL));
int x = std::rand();

тем более в C++0x добавлена библиотека для генерации случайный величин которые имеют различные распределения: от нормального распределения до распределение студента, хи квадрат, гамма распределение и т.д.

Автор: Litkevich Yuriy 16.7.2010, 0:39

Цитата(DEADHUNT @ 16.7.2010, 0:51) *
зачем использовать какие-то непонятные Qt конструкции
те что в Qt можно использовать в разных потоках

Автор: DEADHUNT 16.7.2010, 1:27

Цитата(Litkevich Yuriy @ 16.7.2010, 1:39) *
те что в Qt можно использовать в разных потоках

а из cstdlib нельзя? :blink: там для каждого потока отводится переменная(в VC++ например) с текущем значением(да и вообще реализация скрыта от пользователей).

Автор: Litkevich Yuriy 16.7.2010, 7:52

Цитата(DEADHUNT @ 16.7.2010, 5:27) *
а из cstdlib нельзя?
http://doc.crossplatform.ru/qt/4.6.x/qtglobal.html#qsrand

Автор: eldar85 2.8.2010, 12:59

все же в многопоточности рандом работает не так как хотелось бы, точнее вообще показывает очень часто одно и тоже число в каждом потоке. запускаю я к примеру 10 потоков. запуск каждого потока производится каждые 0,1 сек.

qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()));
объявлял в главной main функции и всюду, эфект почти один и тот же.
генератор числа в небольшом диапазоне, оьычно от 100 до 200.
 int rand = qrand()%100;

но потоки прям один за другим выдают одно и тоже число, затем несколько потоков могут что то иное выдать, но это как исключение. как быть?

Автор: SABROG 2.8.2010, 14:15

Оно и понятно, потоки наверняка почти одновременно запускаются, не успевает даже время пройти. Ты вызови один раз qsrand(), потом вызови qrand() для каждого потока, затем в каждом потоке вызови снова qsrand(), но уже со значениями полученными от предыдущего qrand'a().

Автор: Litkevich Yuriy 2.8.2010, 16:37

собственно троли сделали qsrand вместо srand, для того, чтобы эту функцию можно было в каждом потоке вызывать. И тогда у каждого потока будет своё начальное значение.

Автор: eldar85 2.8.2010, 16:48

получается что то типа такого, объявляем в мэйне

qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()));


затем в каждом потоке
int rand = qrand()%100;
qsrand(rand);


как то так чтоли?


а потоки у меня запускаются каждые 0,1 сек

Автор: Litkevich Yuriy 2.8.2010, 17:20

Цитата(eldar85 @ 2.8.2010, 20:48) *
как то так чтоли?
нет.
функция srand предназначена для задания начального значения Псевдослучайной Последовательности (ПСП). Т.е. её вызывают один раз и всё.
Но если тебе нужно использовать ПСП в нескольких потоках, то в каждом потоке, в самом начале, вызови qsrand, а затем, для получения очередного значения ПСП, только qrand


П.С.
Отличие трольтеховских функций от стандартных:
Если бы ты использовал стандартные srand/rand, вместо qsrand/qrand, то получилось бы так:
каждый вызов srand влиял бы на все потоки, т.е. для всех потоков устанавливалось бы одно и тоже начальное значение.
Справка:
Буква s в названии функции означает seed - сеятель, значение с которого начинается генерация ПСП

Автор: SABROG 2.8.2010, 17:46

Юр, мне кажется это не так.

Цитата
The sequence of random numbers generated is deterministic per thread. For example, if two threads call qsrand(1) and subsequently calls qrand(), the threads will get the same random number sequence.


Последовтельность сгенеренных номеров предопределены для каждого потока. Для примера 2 потока вызывают qsrand(1) и подпоследовательность вызывает qrand(), потоки получат ту же последовательность номеров.

Поэтому я предложил такой вариант:

qsrand(QTime(0,0,0).msecsTo(QTime::currentTime())); // вызов в main()
for (int i = 0; i < threads.size(); ++i) {
    int rand = qrand()%100;
    threads[i].setRandomSeed(rand);
}

void MyThread::run()
{
    qsrand(getRandomSeed());
    ...
    qrand()%100;
}


В итоге распределения "семечек" по потокам может быть таким:

Thread 1 - 1
Thread 2 - 50
Thread 3 - 23
Thread 4 - 78
...
А уж от этих "семечек" мы получаем разную последовательность случайных чисел при вызове qrand() в каждом из потоков.

В принципе можно еще как-нибудь так извернуться: qsrand((int)this)

Автор: eldar85 2.8.2010, 18:40

да, вот это уже очень даже рабочая схема будет я думаю))) спасибо за совет)) завтра буду внедрять)))

Автор: Litkevich Yuriy 2.8.2010, 23:04

Цитата(SABROG @ 2.8.2010, 21:46) *
Для примера 2 потока вызывают qsrand(1) и подпоследовательность вызывает qrand(), потоки получат ту же последовательность номеров.
ты не понял, о чём я написал.
Представь, что не оба потока инициализировали ПСП, а только один, он успел несколько раз дёрнуть генератор. Следующее значение ПСП допустим равно 100.
В этот момент второй поток инициализирует генератор тем же значением что и первый.

Вот в этой ситуации стандартные функции приведут к тому, что у первого потока ПСП собьётся. А при использовании Qt версии этих функций этого не произойдёт.

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)