Случайные числа - страница 4

 
Mak:
Mathemat:
Функция 32768 * MathRand() + MathRand() по идее должна генерировать псевдослучайные равнораспределенные числа от 0 до 32768^2 - 1 = 1073741823, так что дискретностью можно управлять. Проекция этой последовательности на отрезок [0,1] дает дроби с дискретностью менее 1Е-9. Правда, проверить эту функцию на равномерность уже не так просто.
.................
Плохой способ.
Последовательные вызовы MathRand взаимно зависимы, т.е. второй вызов - однозначная функция от результата первого.
При этом известно, что у этих датчиков (конгоруентных) часто имеется такой эффект, когда пары (тройки) последовательных чисел в их псевдослучайной последовательности подчиняются простым закономерностям. В общем такому способу создания псевдослучайных чисел я не доверяю.

Кроме того, судя по разрядности (15-16 бит) генератор построен на 2-х байтовых целых.
У этого ДСЧ не более 64К разных последовательностей, каждая длиной не более 64К чисел.
Дальше последовательность повторяется. И это в лучшем случае.


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

P.S. Псевдослучайная сумма псевдослучайных последовательностей псевдослучайной длины. Можно и продолжить :)

 
lna01 писал (а):

Время от времени перерандомизировать генератор? Только как-то, чтобы это было нерегулярно.
Берите интервал в миллисекундах между N тиками.
 
Mak:
Последовательные вызовы MathRand взаимно зависимы, т.е. второй вызов - однозначная функция от результата первого.
Неверно, Mak. Ты этого просто не проверял, так ведь? Прямое опровержение цитаты см. 'Вопрос от новичка: две кривые в разных окнах' (мое предпоследнее сообщение). Вместе с komposter'ом мы это проверили. Генерировался снова миллиард чисел, но повторения заданной пары последовательных в этом миллиарде встретились только дважды, вместо примерно 30 тысяч повторений каждого из чисел, - так что это не просто "линейный конгруэнтный" генератор, в котором каждое следующее число однозначно зависит от предыдущего... Если ты со мной не согласен - факты в студию!

P.S. Если лень делать код - выложу.

P.P.S. А вот абсолютно гениальный по длине код на Си, который я нашел на Исходниках.ру. Глобальная переменная _rnd имеет последним символом букву "l" ("long"), а не единичку:

long _rnd = 9543l; //это число инициализирует наиболее длинную последовательность ПСВ
double rnd()
{
   static double x = 4.6566128730773926e-10;
   static long ib = 2147483647;
   _rnd *= 65539;
   if( _rnd < 0 )
      _rnd += ( ib + 1 );
   return( ( double ) ( _rnd * x ) );     // интервал [0;1[ 
}
 
Не проверял, согласен ... :))

Проверил, действительно в пределах миллиарда получилось 2 совпадения (видимо случайных).
Сейчас проверяю период повторений этого ДСЧ - похоже это почти 2^31.
Т.е. это скорее всего тот же линейный конгоруентный метод, только из 4 байт нам показывают 2.
Если бы нам показывали все 4, проблем о которых я тут писал не было бы.

Кстати, гениальная функция которую ты привел - это и есть "линейный конгоруентный метод".
Предыдущий член ряда умножается на константу, прибавляется другая константа и все это по модулю.

Решил немного порыться в инете на эту тему.
Наткнулся на свежие разработки - "Вихрь Мерсенна" - последний писк, супер генератор :))
http://www.math.sci.hiroshima-u.ac.jp/%7Em-mat/MT/SFMT/index.html
(там можно скачать исходники на С)

Описание в WikiPedia
https://ru.wikipedia.org/wiki/%D0%92%D0%B8%D1%85%D1%80%D1%8C_%D0%9C%D0%B5%D1%80%D1%81%D0%B5%D0%BD%D0%BD%D0%B0
 
Вот нашел архив с исходниками и готовыми DLL.
Не пробовал, но должны под МТ работать.
Файлы:
mt_dll.zip  37 kb
 
Эхх, а вот и набор тестов для проверки на случайность: https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%81%D1%82%D1%8B_DIEHARD . Как оно все на самом деле серьезно...
 

Ребят, помогите написать алгоритм случайного выбора числа из списка следующих готовых чисел: 1,5; 1,6; 1,7; 1,8; 1,9; 2; 2,1; 2,2; 2,3; 2,4; 2,5

В программировании совсем не шарю...

 
taurus78:

алгоритм случайного выбора числа из списка: 1,5; 1,6; 1,7; 1,8; 1,9; 2; 2,1; 2,2; 2,3; 2,4; 2,5

// скрипт для проверки:
void OnStart()
{
  string Строка="";                  // В эту строку затолкаем полученные 22 числа
   MathSrand(GetTickCount());  // Инициализация генератора случайных чисел
  for(int Счет=0; Счет<22; Счет++)Строка=Строка+"  " +Случайное();  // Набиваем числа через 2 пробела в строку для вывода
  Alert(Строка);
}

double Случайное()                                               // Вот функция, возвращающая нужное значение
{
  return round(15+rand()/32760.0*10.0)/10;   // Здесь получается нужное значение. Сначала округляем, потом делим на 10
}

rand()/32760.0 - это число от 0 до 1
rand()/32760.0*10.0 - это число от 0 до 10
15+rand()/32760.0*10.0 - это число от 15 до 25  после округления round это будут целые числа, а деление на 10 даст нужный результат

Недостаток: числа могут повторяться до 5 раз подряд. Если нужно иначе, исправляется запоминанием предыдущего и повтором при совпадении

Причина обращения: