Функция JavaScript Math.random()
возвращает случайное значение от 0 до 1, автоматически посеянное в зависимости от текущего времени (похоже на Java, я считаю). Тем не менее, я не думаю, что есть какой-то способ установить для вас собственное семя.
Как я могу создать генератор случайных чисел, для которого я могу предоставить свое собственное начальное значение, чтобы он мог генерировать повторяемую последовательность (псевдо) случайных чисел?
javascript
random
seed
scunliffe
источник
источник
Ответы:
Одним из вариантов является http://davidbau.com/seedrandom, который представляет собой замену Math.random () на основе RC4 с возможностью вставки с хорошими свойствами.
источник
Если вам не нужна возможность посева, просто используйте
Math.random()
и создайте вспомогательные функции вокруг нее (например,randRange(start, end)
).Я не уверен, какую ГСЧ вы используете, но лучше знать и документировать ее, чтобы вы знали о ее характеристиках и ограничениях.
Как сказал Старкий, Mersenne Twister - хороший PRNG, но его нелегко реализовать. Если вы хотите сделать это самостоятельно, попробуйте внедрить LCG - это очень просто, имеет приличные качества случайности (не такие хорошие, как у Mersenne Twister), и вы можете использовать некоторые популярные константы.
РЕДАКТИРОВАТЬ: рассмотрите отличные варианты в этом ответе для коротких затравочных реализаций ГСЧ, включая вариант LCG.
источник
this.a * this.state
может привести к числу больше 2 ^ 53. Результатом является ограниченный диапазон выхода, а для некоторых семян возможно очень короткий период. Кроме того, в общем случае использование степени два дляm
результата приводит к некоторым довольно очевидным шаблонам, когда вы все равно расширяете операцию модуля, а не простое усечение, нет причин не использовать простое число.Если вы хотите иметь возможность указать начальное число, вам просто нужно заменить вызовы на
getSeconds()
иgetMinutes()
. Вы можете передать int и использовать половину его mod 60 для значения секунд, а другую половину по модулю 60, чтобы дать вам другую часть.При этом, этот метод выглядит как мусор. Делать правильные генерации случайных чисел очень сложно. Очевидная проблема с этим состоит в том, что начальное число случайных чисел основано на секундах и минутах. Чтобы угадать начальное число и воссоздать ваш поток случайных чисел, нужно всего лишь попробовать 3600 различных секундных и минутных комбинаций. Это также означает, что существует всего 3600 различных возможных семян. Это исправимо, но я бы с самого начала с подозрением отнесся к этому ГСЧ.
Если вы хотите использовать более качественный ГСЧ, попробуйте Mersenne Twister . Это хорошо протестированный и достаточно надежный ГСЧ с огромной орбитой и отличной производительностью.
РЕДАКТИРОВАТЬ: Я действительно должен быть правильным и относиться к этому как генератор псевдослучайных чисел или PRNG.
источник
Я использую порт JavaScript Mersenne Twister: https://gist.github.com/300494 Это позволяет вам установить начальное значение вручную. Кроме того, как упоминалось в других ответах, Mersenne Twister - действительно хороший PRNG.
источник
Код, который вы перечислили, выглядит как Lehmer RNG . Если это так, то
2147483647
это наибольшее 32-разрядное целое число со знаком,2147483647
наибольшее 32-разрядное простое число и48271
множитель полного периода, который используется для генерации чисел.Если это правда, вы можете изменить,
RandomNumberGenerator
чтобы получить дополнительный параметрseed
, а затем установитьthis.seed
вseed
; но вы должны быть осторожны, чтобы убедиться, что начальное число приведет к хорошему распределению случайных чисел (Лемер может показаться странным), но большинство семян будет в порядке.источник
Ниже приведен PRNG, который можно подавать на заказ. Вызов
SeedRandom
вернет случайную функцию генератора.SeedRandom
может вызываться без аргументов, чтобы заполнить возвращаемую случайную функцию текущим временем, или она может быть вызвана с 1 или 2 неотрицательными значениями в качестве аргументов, чтобы заполнить ее этими целыми числами. Из-за точности с плавающей точкой, заполнение только одним значением позволит генератору переключиться в одно из 2 ^ 53 различных состояний.limit
Возвращенная функция генератора случайных значений принимает 1 целочисленный аргумент с именем , предел должен быть в диапазоне от 1 до 4294965886, функция будет возвращать число в диапазоне от 0 до limit-1.Пример использования:
Этот генератор обладает следующими свойствами:
mod
значения являются простыми, в выводе нет простого шаблона, независимо от выбранного предела. Это не похоже на некоторые более простые PRNG, которые демонстрируют некоторые довольно систематические закономерности.источник
for (var i = 0; i < 400; i++) { console.log("input: (" + i * 245 + ", " + i * 553 + ") | output: " + SeedRandom(i * 245, i * 553)(20)); }
Если вы программируете на Typescript, я адаптировал реализацию Mersenne Twister, приведенную в ответе Кристофа Хенкельмана к этой теме, как класс машинописного текста:
Вы можете использовать его следующим образом:
проверьте источник для других методов.
источник
Я обнаружил, что этот код работает, и он отлично работает для получения случайного числа и последующего использования начального числа, но я не совсем уверен, как работает логика (например, откуда взялись числа 2345678901, 48271 и 2147483647).
источник
RandomNumberGenerator
иnextRandomNumber
функции фактически датировать все пути назад к 1996 году , как предполагается, будет Лехмер / LCG ГСЧ. Он использует некоторые умные математические выражения для выполнения арифметики по модулю над 32-битными целыми числами, которые в противном случае были бы слишком малы, чтобы содержать некоторые промежуточные значения. Дело в том, что JavaScript не реализует 32-битные целые числа, а скорее 64-битные числа с плавающей запятой, и поскольку деление не является целочисленным делением, как этот код предполагает, что результат не является генератором Лемера. Это дает некоторый результат, который кажется случайным, но гарантии генератора Лемера не применяются.createRandomNumber
функция является более поздним дополнением, она делает почти все неправильно, в частности она создает новый RNG каждый раз, когда он вызывается, что означает, что все вызовы в быстрой последовательности будут использовать один и тот же float. В данном коде практически невозможно'a'
соединиться с чем-либо, кроме'1'
и'red'
.Хорошо, вот решение, на котором я остановился.
Сначала вы создаете начальное значение с помощью функции "newseed ()". Затем вы передаете начальное значение в функцию "srandom ()". Наконец, функция «srandom ()» возвращает псевдослучайное значение в диапазоне от 0 до 1.
Ключевой бит в том, что начальное значение хранится внутри массива. Если бы это было просто целое число или число с плавающей запятой, значение будет перезаписываться при каждом вызове функции, поскольку значения целых чисел, чисел с плавающей запятой, строк и т. Д. Сохраняются непосредственно в стеке, а не только в указателях, как в случае массивов и другие объекты. Таким образом, ценность семени остается неизменной.
Наконец, можно определить функцию "srandom ()" так, чтобы это был метод объекта "Math", но я оставлю это на ваше усмотрение, чтобы разобраться. ;)
Удачи!
JavaScript:
Lua 4 (моя личная целевая среда):
источник
seedobj[0] * seedobja
может привести к числу больше 2 ^ 53. Результатом является ограниченный диапазон выхода, а для некоторых семян возможно очень короткий период.