Страница 1 из 2

Воспроизвести рандомы

СообщениеДобавлено: 25.05.2016 03:06:54
Дож
Есть программа на паскале. Она использует генератор случайных чисел (стандартные функции Random). Задача: сохранить из этой программы такую информацию, чтобы потом можно было бы воспроизвести ту же последовательность случайных чисел в этой же программе.

Проблема: информация должна быть кроссплатформенной, т.е. в одной ОС её сохранили, а на другой по ней запустили программу. Из-за этого условия я не уверен, что достаточно будет сохранить RandSeed, — насколько RandSeed и Random кроссплатформенны?

Сохранять чиселки с каждого вызова Random очень не хочется.

Предполагается, что программа для всех платформ компилируется одной версией fpc.

Вариант «Напиши и используй свой рандом» не предлагать.

Re: Воспроизвести рандомы

СообщениеДобавлено: 25.05.2016 03:44:02
скалогрыз
Дож писал(а):Из-за этого условия я не уверен, что достаточно будет сохранить RandSeed, — насколько RandSeed и Random кроссплатформенны?

кроссплатформенный, т.к. реализован в RTL-е, и не зависит от системных функций.
Единственная тонкость, что сама реализация random-a может в RTL-е поменяться в очередной версии FPC (в баг трекере регулярно появляются более рандомные рандомы() :D)
но в таком случае достаточно будет скопировать нужную реализацию.

Randseed - наше всё!

Re: Воспроизвести рандомы

СообщениеДобавлено: 25.05.2016 04:17:46
Дож
Как раз за версии fpc не боюсь, так как собирать буду одной.

А 32/64-bit, little/big endian — тоже не влияют? Например, я при переходе с little на big свапну части, а по факту в реализации используется последовательность байт…

Re: Воспроизвести рандомы

СообщениеДобавлено: 25.05.2016 06:12:56
скалогрыз
Дож писал(а):А 32/64-bit, little/big endian — тоже не влияют?

Не влияют. Как пишет документация на рандом, в основе математический алгоритм Вихрь Мерсена
Алгоритм математический, на конкретную платформу не привязан.
В реализации каких-либо платформо специфичных хаков нет (такие платформо-привязанные хаки обычно встречаются в игровых движках)

Если пугают операции вроде shr и shl, то на самом деле они дают одинаковый результат в big-end и little-end платформах (увеличивая/уменьшая число). Внутренняя реализация привязана к 32-битным числам на любой платформе (включая dos).
например random(int64) даже на 64-х битной платформе это двойной вызов к random(int32)

...главное Randseed между little и big endian правильно передать :) предлагаю в текстовой форме!

Re: Воспроизвести рандомы

СообщениеДобавлено: 25.05.2016 06:31:18
sign
Написать самому.
Дело не сложное, зато будет гарантия тому, что всегда будет одна и та же последовательность, при одних исходных данных, засылаемых в генератор.

Добавлено спустя 3 минуты 29 секунд:
Скачайте себе Кнута, если нет.
Во втором томе подробнейшим образом разобраны всяческие алгоритмы генерации случайных чисел.

Re: Воспроизвести рандомы

СообщениеДобавлено: 25.05.2016 10:54:42
Дож
Дело не сложное, зато будет гарантия тому, что всегда будет одна и та же последовательность, при одних исходных данных, засылаемых в генератор.

Предположим, я так и сделал. Допустим, в программе вызывается функция f из некоторой сторонней библиотеки A, а внутри функции используется стандартный Random. Если всё оставить нетронутым, то этот вызов f может порушить детерменированность. Что делать? Бегать по всем библиотекам и подменять Random на DojRandom, добавляя зависимостью свою модуль? (Так себе вариант.) Написать свой system.pas, постоянно пересобирать fpc rtl под него? (Тоже так себе вариант.)

Re: Воспроизвести рандомы

СообщениеДобавлено: 25.05.2016 11:35:36
zub
>>Вариант «Напиши и используй свой рандом» не предлагать.
Это единственный 100% вариант. Т.к. несмотря на то что random кроссплатформенный, гарантии того что на каконить платформе в какойнить библиотеке гденибудь он не используется нет.
Сохранили randseed, а TVasyaSuperButton на платформе win16 вызывает стандартный random при нажатии на эту суперкнопку из какихто хитрых соображений - последовательность нарушится...

Re: Воспроизвести рандомы

СообщениеДобавлено: 25.05.2016 11:58:11
Дож
TVasyaSuperButton на платформе win16 вызывает стандартный random при нажатии на эту суперкнопку из какихто хитрых соображений - последовательность нарушится...

Это как раз не сильно беспокоит, я хочу записать все «входные данные» в программу, соответственно нажатие на эту суперкнопку произойдёт в тот же момент и дёрнет ту же чиселку, не нарушив последовательность. А вот помнить про свой рандом и лезть постоянно во все библиотеки и что-то в них править — сомнительная практика, не фанат такого.

Сохранили randseed

Во, расскажите лучше подробнее как сохранять по науке :) Как число или как последовательность байт в памяти? Я в коде вижу shr и shl и прибитые гвоздём константы (т.е. как число?)
Код: Выделить всё
// rtl/inc/system.inc
function mtwist_u32rand: cardinal;
begin
  if (RandSeed<>OldRandSeed) or
     (mt_index=MTWIST_N+1) then
    begin
      mtwist_init(RandSeed);
      { Detect resets of randseed

        This will break if someone coincidentally uses not(randseed) as the
        next randseed, but it's much more common that you will reset randseed
        to the same value as before to regenerate the same sequence of numbers
      }
      RandSeed:=not(RandSeed);
      OldRandSeed:=RandSeed;
    end;
  if mt_index=MTWIST_N then
    mtwist_update_state;
  result:=mt_state[mt_index];
  inc(mt_index);
  result:=result xor (result shr 11);
  result:=result xor ((result shl 7) and cardinal($9D2C5680));
  result:=result xor ((result shl 15) and cardinal($EFC60000));
  result:=result xor (result shr 18);
end;

Re: Воспроизвести рандомы

СообщениеДобавлено: 25.05.2016 12:19:44
zub
Как не сохраняй устанавливаться та он будет уже в виде cardinal
Код: Выделить всё
procedure mtwist_init(seed: cardinal);
var
  i: longint;
begin
  mt_state[0]:=seed;
  for i:=1 to MTWIST_N-1 do
    mt_state[i]:=cardinal(1812433253) * (mt_state[i-1] xor (mt_state[i-1] shr 30)) + i;
   { still need to update the state }
  mt_index:=MTWIST_N;
end;

Если сохранять бинарно - то фиксировать endian при записи, например всегда писать как little и свапить по нужде на платформе где читается, если она big.
Если текстом, то вообще заморачиваться ничем ненадо.

>>А вот помнить про свой рандом и лезть постоянно во все библиотеки и что-то в них править — сомнительная практика, не фанат такого.
В программе так много мест с рандомом который нужно сохранять? Если разделить на свой\системный и выделить нужные места - то лазить по чужим библиотекам не придется.
простейший рандом выглядит както так:
Код: Выделить всё
...
randseed:integer{cardinal};
...
procedure MyRandom:integer{cardinal};
begin
           randseed:=randseed * $343fd;
           randseed:=randseed + $269ec3;
           result:=randseed;
end;

Re: Воспроизвести рандомы

СообщениеДобавлено: 25.05.2016 12:32:55
Дож
Ок, спасибо, попробую сохранять seed.

Если разделить на свой\системный и выделить нужные места - то лазить по чужим библиотекам не придется.

На самом деле даже в своём коде не очень хочу использовать свой рандом, чтобы не плодить библиотек и зависимостей :) Если прокатит с RandSeed, то это реально очень упростит поддержку кода.

Для надёжности, возможно, добавлю сохранение «контрольных рандомов» (вызванный в определённые моменты Random специально для подтверждения идентичности воспроизводимой последовательности).

простейший рандом выглядит както так:

Вот что-что, а клепать вилосипеды я точно не боюсь :)

Re: Воспроизвести рандомы

СообщениеДобавлено: 28.05.2016 19:57:47
Cheb
Вариант «Напиши и используй свой рандом» не предлагать.

Скопипасть фрипаскалевский рандом в собственный модуль. Тогда эту копию будут использовать только твои модули.

Re: Воспроизвести рандомы

СообщениеДобавлено: 29.05.2016 00:53:43
Ism
Какой смысл в рандоме если его надо повторять ?
Тогда уж создать файл с шумом и подкладывать, кроссплатформенно, надежно :)

Re: Воспроизвести рандомы

СообщениеДобавлено: 29.05.2016 01:16:57
Дож
Cheb писал(а):
Вариант «Напиши и используй свой рандом» не предлагать.

Скопипасть фрипаскалевский рандом в собственный модуль. Тогда эту копию будут использовать только твои модули.

А как быть с НЕ моими модулями, которые используются в программе и используют рандом?

Какой смысл в рандоме если его надо повторять ?
Тогда уж создать файл с шумом и подкладывать, кроссплатформенно, надежно

Мне не нужен невоспроизводимый рандом, у меня не криптография.

Re: Воспроизвести рандомы

СообщениеДобавлено: 29.05.2016 01:33:53
Mirage
Дож писал(а):Предположим, я так и сделал. Допустим, в программе вызывается функция f из некоторой сторонней библиотеки A, а внутри функции используется стандартный Random.


А если там Randomize() используется?

Re: Воспроизвести рандомы

СообщениеДобавлено: 29.05.2016 01:38:44
Дож
Mirage писал(а):
Дож писал(а):Предположим, я так и сделал. Допустим, в программе вызывается функция f из некоторой сторонней библиотеки A, а внутри функции используется стандартный Random.


А если там Randomize() используется?

В выбранном пока что решении — я узнаю по контрольным рандомам, что что-то пошло не так и буду смотреть что именно. А так — это тоже проблема, конечно.