Воспроизвести рандомы
Модератор: Модераторы
Воспроизвести рандомы
Есть программа на паскале. Она использует генератор случайных чисел (стандартные функции Random). Задача: сохранить из этой программы такую информацию, чтобы потом можно было бы воспроизвести ту же последовательность случайных чисел в этой же программе.
Проблема: информация должна быть кроссплатформенной, т.е. в одной ОС её сохранили, а на другой по ней запустили программу. Из-за этого условия я не уверен, что достаточно будет сохранить RandSeed, — насколько RandSeed и Random кроссплатформенны?
Сохранять чиселки с каждого вызова Random очень не хочется.
Предполагается, что программа для всех платформ компилируется одной версией fpc.
Вариант «Напиши и используй свой рандом» не предлагать.
Проблема: информация должна быть кроссплатформенной, т.е. в одной ОС её сохранили, а на другой по ней запустили программу. Из-за этого условия я не уверен, что достаточно будет сохранить RandSeed, — насколько RandSeed и Random кроссплатформенны?
Сохранять чиселки с каждого вызова Random очень не хочется.
Предполагается, что программа для всех платформ компилируется одной версией fpc.
Вариант «Напиши и используй свой рандом» не предлагать.
Дож писал(а):Из-за этого условия я не уверен, что достаточно будет сохранить RandSeed, — насколько RandSeed и Random кроссплатформенны?
кроссплатформенный, т.к. реализован в RTL-е, и не зависит от системных функций.
Единственная тонкость, что сама реализация random-a может в RTL-е поменяться в очередной версии FPC (в баг трекере регулярно появляются более рандомные рандомы()
но в таком случае достаточно будет скопировать нужную реализацию.
Randseed - наше всё!
Как раз за версии fpc не боюсь, так как собирать буду одной.
А 32/64-bit, little/big endian — тоже не влияют? Например, я при переходе с little на big свапну части, а по факту в реализации используется последовательность байт…
А 32/64-bit, little/big endian — тоже не влияют? Например, я при переходе с little на big свапну части, а по факту в реализации используется последовательность байт…
Дож писал(а):А 32/64-bit, little/big endian — тоже не влияют?
Не влияют. Как пишет документация на рандом, в основе математический алгоритм Вихрь Мерсена
Алгоритм математический, на конкретную платформу не привязан.
В реализации каких-либо платформо специфичных хаков нет (такие платформо-привязанные хаки обычно встречаются в игровых движках)
Если пугают операции вроде shr и shl, то на самом деле они дают одинаковый результат в big-end и little-end платформах (увеличивая/уменьшая число). Внутренняя реализация привязана к 32-битным числам на любой платформе (включая dos).
например random(int64) даже на 64-х битной платформе это двойной вызов к random(int32)
...главное Randseed между little и big endian правильно передать
Написать самому.
Дело не сложное, зато будет гарантия тому, что всегда будет одна и та же последовательность, при одних исходных данных, засылаемых в генератор.
Добавлено спустя 3 минуты 29 секунд:
Скачайте себе Кнута, если нет.
Во втором томе подробнейшим образом разобраны всяческие алгоритмы генерации случайных чисел.
Дело не сложное, зато будет гарантия тому, что всегда будет одна и та же последовательность, при одних исходных данных, засылаемых в генератор.
Добавлено спустя 3 минуты 29 секунд:
Скачайте себе Кнута, если нет.
Во втором томе подробнейшим образом разобраны всяческие алгоритмы генерации случайных чисел.
Дело не сложное, зато будет гарантия тому, что всегда будет одна и та же последовательность, при одних исходных данных, засылаемых в генератор.
Предположим, я так и сделал. Допустим, в программе вызывается функция f из некоторой сторонней библиотеки A, а внутри функции используется стандартный Random. Если всё оставить нетронутым, то этот вызов f может порушить детерменированность. Что делать? Бегать по всем библиотекам и подменять Random на DojRandom, добавляя зависимостью свою модуль? (Так себе вариант.) Написать свой system.pas, постоянно пересобирать fpc rtl под него? (Тоже так себе вариант.)
>>Вариант «Напиши и используй свой рандом» не предлагать.
Это единственный 100% вариант. Т.к. несмотря на то что random кроссплатформенный, гарантии того что на каконить платформе в какойнить библиотеке гденибудь он не используется нет.
Сохранили randseed, а TVasyaSuperButton на платформе win16 вызывает стандартный random при нажатии на эту суперкнопку из какихто хитрых соображений - последовательность нарушится...
Это единственный 100% вариант. Т.к. несмотря на то что random кроссплатформенный, гарантии того что на каконить платформе в какойнить библиотеке гденибудь он не используется нет.
Сохранили randseed, а TVasyaSuperButton на платформе win16 вызывает стандартный random при нажатии на эту суперкнопку из какихто хитрых соображений - последовательность нарушится...
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;
Как не сохраняй устанавливаться та он будет уже в виде cardinal
Если сохранять бинарно - то фиксировать endian при записи, например всегда писать как little и свапить по нужде на платформе где читается, если она big.
Если текстом, то вообще заморачиваться ничем ненадо.
>>А вот помнить про свой рандом и лезть постоянно во все библиотеки и что-то в них править — сомнительная практика, не фанат такого.
В программе так много мест с рандомом который нужно сохранять? Если разделить на свой\системный и выделить нужные места - то лазить по чужим библиотекам не придется.
простейший рандом выглядит както так:
Код: Выделить всё
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;Ок, спасибо, попробую сохранять seed.
На самом деле даже в своём коде не очень хочу использовать свой рандом, чтобы не плодить библиотек и зависимостей :) Если прокатит с RandSeed, то это реально очень упростит поддержку кода.
Для надёжности, возможно, добавлю сохранение «контрольных рандомов» (вызванный в определённые моменты Random специально для подтверждения идентичности воспроизводимой последовательности).
Вот что-что, а клепать вилосипеды я точно не боюсь :)
Если разделить на свой\системный и выделить нужные места - то лазить по чужим библиотекам не придется.
На самом деле даже в своём коде не очень хочу использовать свой рандом, чтобы не плодить библиотек и зависимостей :) Если прокатит с RandSeed, то это реально очень упростит поддержку кода.
Для надёжности, возможно, добавлю сохранение «контрольных рандомов» (вызванный в определённые моменты Random специально для подтверждения идентичности воспроизводимой последовательности).
простейший рандом выглядит както так:
Вот что-что, а клепать вилосипеды я точно не боюсь :)
Вариант «Напиши и используй свой рандом» не предлагать.
Скопипасть фрипаскалевский рандом в собственный модуль. Тогда эту копию будут использовать только твои модули.
Какой смысл в рандоме если его надо повторять ?
Тогда уж создать файл с шумом и подкладывать, кроссплатформенно, надежно
Тогда уж создать файл с шумом и подкладывать, кроссплатформенно, надежно
Cheb писал(а):Вариант «Напиши и используй свой рандом» не предлагать.
Скопипасть фрипаскалевский рандом в собственный модуль. Тогда эту копию будут использовать только твои модули.
А как быть с НЕ моими модулями, которые используются в программе и используют рандом?
Какой смысл в рандоме если его надо повторять ?
Тогда уж создать файл с шумом и подкладывать, кроссплатформенно, надежно
Мне не нужен невоспроизводимый рандом, у меня не криптография.
-
Mirage
- энтузиаст
- Сообщения: 881
- Зарегистрирован: 06.05.2005 20:29:07
- Откуда: Russia
- Контактная информация:
Дож писал(а):Предположим, я так и сделал. Допустим, в программе вызывается функция f из некоторой сторонней библиотеки A, а внутри функции используется стандартный Random.
А если там Randomize() используется?
Mirage писал(а):Дож писал(а):Предположим, я так и сделал. Допустим, в программе вызывается функция f из некоторой сторонней библиотеки A, а внутри функции используется стандартный Random.
А если там Randomize() используется?
В выбранном пока что решении — я узнаю по контрольным рандомам, что что-то пошло не так и буду смотреть что именно. А так — это тоже проблема, конечно.
