%RANDOM% возвращает один и тот же вывод при каждом выполнении

Следующий скрипт:

@echo off
setlocal EnableDelayedExpansion
set n=0
for /R %%f in (./*.avi;./*.mp4) do (
   set /A n+=1
   set "file[!n!]=%%f"
)
set /A "rand=(n*%random%)/32768+1"
ECHO %rand%
ECHO "!file[%rand%]!"
endlocal
PAUSE

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

Спасибо


person Adam Pitt    schedule 25.10.2015    source источник


Ответы (2)


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

Но последовательные выполнения одних и тех же или разных пакетных файлов внутри одного и того же экземпляра cmd будут извлекать разные (или нет, это случайные) «случайные» последовательности.

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

Если n одинаково или похоже для каждого выполнения, а %random% возвращает значение, близкое к тому, которое было возвращено в предыдущем выполнении (как вы описываете), то n*%random% вернет результат, близкий к единице в предыдущем выполнении. При делении на 32768 любая разница будет отброшена, и вы получите тот же выбранный файл.

В этом случае лучше использовать оператор по модулю. Будучи остатком от деления, легче получить другой результат лишь немного отличающегося начального случайного значения.

set /a "rand=%random% %% n + 1"
person MC ND    schedule 25.10.2015

Мне не удалось воспроизвести это, но если проблема связана с тем, что %random% запрашивается с крошечными интервалами и изменяется только в небольших количествах, то решением может быть другая формула. В следующем варианте вы получите другой результат, даже если %random% изменится только на 1:

set /A "rand=(%random% %% n)+1"
person trincot    schedule 25.10.2015
comment
Не могли бы вы изменить объяснение того, почему этот синтаксис отвечает на вопрос? Ответы, содержащие только код, не рекомендуются, поскольку они не учат решению. - person Nathan Tuggy; 26.10.2015
comment
Действительно, это было слишком коротко. Я отредактировал свой ответ. Спасибо. - person trincot; 26.10.2015