задача
Если положительное целое число n
меньше 2^30
указанного в качестве входного значения любым выбранным вами способом, ваш код должен выдавать случайное целое число между 0
и n
включительно. Число, которое вы генерируете, должно выбираться случайным образом равномерно . То есть каждое значение от 0
до n
должно происходить с равной вероятностью (см. Правила и предостережения).
Правила и предостережения
Ваш код может предполагать, что любой генератор случайных чисел, встроенный в ваш язык или стандартную библиотеку, который утверждает, что он является равномерно случайным, на самом деле является единообразным. То есть вам не нужно беспокоиться о качестве используемого вами случайного источника. Тем не мение,
- Вы должны установить, что если используемый вами случайный источник является однородным, то ваш код правильно выводит равномерное случайное целое число из
0
вn
. - Любые аргументы при вызове встроенной или библиотечной случайной функции должны быть постоянными. То есть они должны быть полностью независимы от входного значения.
- Ваш код может завершиться с вероятностью 1, а не гарантированно завершить.
Заметки
randInt(0,n)
недопустимо, поскольку принимает входные данные в качестве аргумента встроенной или библиотечной функции.rand()%n
не будет давать равномерное случайное число в целом. В качестве примера, приведенного Betseg, еслиintmax == 15
иn = 10
, то вы будете иметь гораздо больше шансов,0-5
чем6-10
.floor(randomfloat()*(n+1))
также не будет давать равномерное случайное число в целом из-за конечного числа различных возможных значений с плавающей запятой между 0 и 1.
code-golf
number
random
probability-theory
totallyhuman
источник
источник
rng()
обеспечивает0
-100
, еслиn = 75
и функция естьrng()%75
, то 0-25 будет более распространенным ...)Ответы:
x86 машины с
rdrand
инструкцией, 10 байтМашинный код
Вход находится в регистре,
rdi
а выход - вrax
.Это учитывает SYS V AMD64 ABI, поэтому код эффективно реализует функцию C
с 32-битным целым
Инструкция
rdrand
описана IntelИмея дело с CSRNG, подразумевается, что распределение является однородным, в любом случае, цитируя NIST SP 800-90A:
Процедура генерирует случайное число и, если оно не строго больше, чем входное значение, оно возвращается.
В противном случае процесс повторяется.
Поскольку он
eax
является 32-битным,rdrand
возвращает число от 0 до 2 32 -1, поэтому для каждого n в [0, 2 32 -1] число ожидаемых итераций равно 2 32 / (n + 1), которое определено для всех n в [0, 2 30 ).источник
jnc
?rdrand
устанавливает, вернут лиCF
верные данные. Данные могут быть недействительными, потому что слишком много запросов истощило пул энтропии. Смотрите руководство для rdrand и это .Желе ,
76 байтСпасибо @JonathanAllan за отыгрывание 1 байта!
Не может быть запущен на TIO, потому что (16!)! это огромное количество.
Как это работает
источник
Mathematica, 29 байт
Основано на ответе желе Денниса .
Я бы не рекомендовал на самом деле запустить это.
2e9!
это довольно большое число ...Оказывается, самое короткое время - создать огромное число, которое делится на все возможные входные данные, и сопоставить результат с требуемым диапазоном с помощью простого модуля.
Отбор выборки, 34 байта
Мой старый подход, который привел к несколько более интересному коду:
Основная отбраковочная выборка. Мы инициализируем вывод 13! (который больше, чем максимальный вход 2 30 ), а затем несколько раз заменить его случайным целым числом от 0 до 13! до тех пор, пока значение больше, чем вход.
источник
Брахилог , 9 байт
Попробуйте онлайн!
Это использует,
13!
как в ответе Мартина Эндера (13ḟ
на один байт меньше2^₃₀
).ṙ
реализуется с использованиемrandom_between/3
, которое при копании своего источника использует то, сrandom_float/0
чем связано, иrandom/1
использует алгоритм Мерсенна Твистера, который является единым для наших целей.объяснение
источник
Пролог (SWI) , 38 байт
Работает методом отбраковки.
Генерируйте случайное число от 0 до 2 ^ 31-1 = 2147483647 до тех пор, пока не будет найдено одно значение, меньшее или равное входному значению.
Я чувствую, как будто я мог бы использовать разрез вместо других, но я не понимаю, как.
источник
repeat
, но в итоге получилось бы на 3 байта длиннее ... Я не уверен, что есть более короткий способ иметь бесконечные точки выбора, чем повторение.,!.
принудительного возврата, но либо я помню это неправильно, либо это не применимо к этому решению.Лабиринт , 63 байта
(Спасибо @MartinEnder за помощь в игре в гольф)
Лабиринт - это двумерный язык, и его единственным источником случайности является ситуация, подобная следующей:
Предположим, указатель инструкции находится на
x
и движется вниз. Затем он попадает на<
, который, если вершина стека равна 0 (что всегда имеет место в реальной программе выше), сдвигает текущую строку влево на 1:Указатель инструкции теперь
<
движется вниз. На перекрестке Лабиринт поворачивается в зависимости от вершины стека - отрицательный - поворот влево, положительный - поворот вправо, а ноль - движение вперед. Если в этом месте вершина стека все еще равна нулю, мы не можем двигаться вперед или назад, поскольку пути нет, поэтому Лабиринт будет случайным образом поворачивать налево или поворачивать направо с равной вероятностью.По сути, вышеприведенная программа использует функцию случайности для генерации 100-битных чисел (
#00
здесь указано 100 ) и продолжает цикл до тех пор, пока он не сгенерирует число<= n
.Для тестирования, вероятно, будет полезно использовать
#0"
вместо этого для 10-битных чисел, с тем,"
чтобы быть неоперативным путем. Попробуйте онлайн!Грубое объяснение:
источник
Python, 61 байт
Изменить: Обновлено, чтобы избежать запрещенной формы
Edit2: сохранено 2 байта, спасибо @ JonathanAllan
Edit3: заплатил 2 байта за полнофункциональное решение - еще раз спасибо @JonathanAllan
Edit4: удалено
f=
, сохранение 2 байтаEdit5: еще 1 байт благодаря @ JonathanAllan
Edit6: сохранено еще 2 байта благодаря @ JonathanAllan
К настоящему моменту, мерзавец обвиняет меня в плохих вещах, а Джонатан Аллан - в том, что помогает.
Edit7: когда идет дождь, он льет - еще 2 байта
Edit8: и еще 2 байта
источник
n
, но вы можете сохранить два байта, когда исправите это, используяfrom random import*
и удаляяr.
....*(-~n*1.0/2**30))
а не...*((n+1)*1.0/2**30))
randrange
кажется, принимает поплавок, поэтомуlambda n,x=2.**30:int(randrange(x)*-~n/x)
сохраняет еще две [править ...] четыре!Python 2 , 61 байт
Псевдослучайно выбирает целые числа между 0 и k для всех значений k между 0 и 2 31 - 2 , затем принимает целое число, соответствующее k = n .
источник
Пакетная, 64 байта
%random%
дает только 15 бит случайности, поэтому я должен объединить два случайных числа. Цикл до тех пор, пока случайное значение не окажется в желаемом диапазоне, поэтому медленно для низкого уровняn
; 98 байт для более быстрой версии:источник
n
?call
, вызов пакетного сценария завершает текущий сценарий.MATL , 12 байт
Благодаря @AdmBorkBork и к @Suever рассказал мне , как отключить кэш TIO.
Попробуйте онлайн! ,
При этом используется метод отклонения : генерировать случайное целое число из
0
в2^30-1
и повторять, пока оно превышает входные данныеn
. Это гарантированно завершится с вероятностью1
, но среднее число итераций равно2^30/n
, и поэтому это занимает очень много времениn
значительно меньше, чем2^30
.источник
JavaScript (ES6),
5554 байтаГенерирует целые числа в диапазоне [0 ... 2 k - 1] , где k - наименьшее целое число, такое, что 2 k больше, чем n . Повторяется до тех пор, пока результат не попадет в [0 ... n] .
Зачем?
Это основано на следующих предположениях:
Внутри псевдослучайные целочисленные значения, генерируемые механизмом JS для подачи,
Math.random()
являются однородными в течение любого интервала [0 ... 2 k -1] (с k <32 ).После умножения на точную степень 2 возвращаемые значения с плавающей точкой IEEE 754
Math.random()
остаются одинаковыми в течение таких интервалов.Если кто-то может подтвердить или опровергнуть эти гипотезы, пожалуйста, дайте мне знать в комментариях.
демонстрация
Создает 1 миллион значений в [0 ... 2] и отображает статистику результатов.
Показать фрагмент кода
источник
Bash (+ coreutils), 44 байта
/ dev / решение на основе urandom
Считает 32-разрядные целые числа без знака
/dev/urandom
и отфильтрует их,awk
пока не найдет одно в заданном диапазоне, а затемsed q
прервет конвейер.источник
Haskell, 70 байт
Не очень эффективный алгоритм, но он работает. Он генерирует бесконечный список целых чисел (или, если необходимо, с плавающей точкой, из-за системы типов Хаскелла), ограниченный [0,2 ^ 30], и принимает первое, меньшее или равное n. Для малых русских это может занять много времени. Случайные числа должны быть равномерно распределены, как указано в документации для randomR, поэтому все числа в интервале [0,2 ^ 30] должны иметь одинаковую вероятность (1 / (2 ^ 30 + 1)), поэтому все числа в [ 0, n] имеют одинаковую вероятность.
Альтернативная версия:
Эта версия ужасна, но сохраняет целый байт.
randoms
использует произвольный диапазон, определенный типом, чтобы генерировать бесконечный список чисел. Это может включать в себя негативы, поэтому нам нужно сопоставить его сabs
положительным значением (или нулем). Это очень медленно для любых значений n, которые не являются абсурдно большими. РЕДАКТИРОВАТЬ : я понял позже, что эта версия не распределена равномерно, потому что вероятность получения 0 хуже, чем другие числа из-за использованияabs
. Для того, чтобы произвести некоторое количествоm
генератора может производитьm
или ,-m
но в случае 0 0 только сам будет работать, поэтому его вероятность равна половина остальных чисел.источник
Желе , 9 байт
Попробуйте онлайн! - код выше не будет работать на TIO, поскольку диапазон размера 16! сначала должен быть построен (не говоря уже о том, что их затем нужно перетасовать, а затем отфильтровать!), так что это то же самое в гораздо меньшем масштабе, повторяется 30 раз для входа 3 с пределом 10.
Как?
Примечание: было бы более чем в тысячу раз эффективнее для того же подсчета байтов, если
ȷ⁵
бы он делал то, что наивно ожидал, и возвращал бы десять к десяти, но это не так, поскольку⁵
не оценивается как буквальная десятка, которая будет использоваться поȷ...
числовому литералу, а вместо этого анализируются два отдельных литерала,ȷ
причем его показатель по умолчанию равен трем, что дает тысячу, а⁵
дает десять.источник
JDK 9 на jshell,
7559 байтиспользование
OptionalInt
. Правила не указывают, что возвращаемый тип должен быть примитивным, и я считаю,OptionalInt
что допустимое представление результата.источник
Optional
принято ли. Я бы подтвердил с плакатом на вашем месте. Кроме того, нет необходимости считать все назначение; достаточно лямбда-выражения.n
иnew Random()
.PHP, 30 байт
Беги с
echo <N> | php -Rn '<code>'
.выбирает случайное число от 0 до
getrandmax()
(2 ** 31-1 на моей 64-битной машине);повторяется, пока это больше, чем вход.
Это может занять некоторое время ... моему AMD C-50 (1 ГГц) потребовалось от 0,3 до 130 секунд
N=15
.Более быстрый способ для среднего
N
( 46 байт ):или
берет
N+1
случайные целые числа, суммирует их и принимает по модулюN+1
.C-50 нуждается в ок. 8 секунд на 1 миллион пробежек.
Неверное решение для 19 байтов :
источник
PowerShell , 35 байт
Попробуйте онлайн!
Еще один метод отбора проб отклонения. Это бесконечный
for
цикл, устанавливая значение ,$a
чтобы бытьRandom
целое число между0
и1gb
(= 1073741824 = 2^30
), и продолжает цикл до тех пор, что является целым числом-g
ля большейt
хань вход$args
. Когда цикл завершен, мы просто включаем$a
конвейер и вывод неявен.Примечание. Это займет много времени, если введено небольшое число.
источник
Python 2 ,
7269 байт-3 байта благодаря xnor (переопределить
id
встроенную переменную)Попробуйте онлайн!
randrange(2**30)
производит псевдо-равномерно распределенное число (Mersenne Twister 2 19937-1 ) из диапазона [0,2 30 ) . Такn
как гарантированно будет меньше 2 30, это можно просто вызывать повторно, пока оно не будет больше, чем вход. Ожидается, что для очень низких значений потребуется долгое времяn
, но обычно он работает в течение одной минуты, даже для входов, таких как 50.источник
r=''
как «бесконечность». Или, что еще лучше, не инициализируйтеr
и вместо этого используйтеid
вездеr
.Perl 6 , 29 байт
Вдохновлено решением Mathematica Мартина Эндера .
Генерирует ленивую бесконечную последовательность случайных целых чисел от 0 до 2 ^ 30-1 и выбирает первое, которое находится между 0 и входом.
Попробуйте онлайн!
источник
05AB1E , 11 байт
Попробуйте онлайн!
объяснение
Поскольку список
[0 ... 2147483648]
слишком велик для TIO,1.000.000
вместо него используется ссылка .Альтернативное (в среднем) намного более быстрое 11-байтовое решение
Попробуйте онлайн
объяснение
источник
žJL.R%
на 6, если я не пропустил что-то огромное. Нажмите 2 ^ 32, список от 0 до 2 ^ 32, случайный выбор. Модуль ввода. Будет абсолютно ввернуть эффективность, которая у вас есть.I
7 байт, чтобы получить аргументы для модуля в правильном порядке (и, возможно,Ý
вместоL
), но в остальном это, безусловно, более короткое решение. Я видел, как Деннис делал это в своем ответе на желе, но так как это была моя первая идея, я сохранил это. Поскольку этот подход отличается от этого, вы можете опубликовать его как отдельный ответ.DI‹Ï
бы избежать петли.0
почти всегда приводит к почти бесконечному циклу, что затрудняет завершение. Хотя решение допускает возможность завершения во всех сценариях, оно не гарантируется из-за случайности.Python 2, 89 байт
объяснение
Это очень неэффективно, так как создает 2 ^ 31 целых чисел, перемешивает и фильтрует их.
Я не вижу смысла делиться ссылкой TIO, где создаются такие большие списки, поэтому здесь ссылка TIO для
n
= 100.Попробуйте онлайн!
источник
Java 8,
8483807162 байта-1 байт благодаря @ OliverGrégoire .
-3 байта благодаря @Jakob .
-9 байтов, преобразующих Java 7 в Java 8.
-9 байтов путем изменения
java.util.Random().nextInt(1<<30)
на(int)(Math.random()*(1<<30))
.Объяснение:
Попробуй это здесь.
ПРИМЕЧАНИЕ. Очевидно, что для небольших входов может потребоваться очень много времени.
Пример вывода:
источник
2^30
=1073741824
. Вы предпочли использовать-1>>>1
(=2147483647
). Но это существует:1<<30
что в точности равно2^30
; и на 1 байт короче.int c(int n){int r;for(;(r=new java.util.Random().nextInt(1<<30))>n;);return r;}
?Math.random()
вместоjava.util.Random().nextInt
.Python 3, 51 байт
Вот Python-решение с неортодоксальным случайным источником.
Попробуйте онлайн!
Так что, чтобы сломать это.
Получает входной номер и добавляет
1
к нему.Создает набор
{0, 1, 2, 3, 4, ... n}
для всех возможных результатов.Берет набор, преобразует его в список и берет первый элемент.
Это работает, потому что в Python 3 порядок
set()
устанавливается PYTHONHASHSEED ( не может быть получен, но устанавливается при выполнении скрипта).Правда, я предполагаю, что это равномерное распределение, так как
hash()
значение назначается случайным образом, и я смотрю на случайный выбор значения с определенным значениемhash()
, а не просто на возврат самогоhash(input())
себя.Если кто-нибудь знает, является ли это унифицированным дистрибутивом или как я могу это проверить, прокомментируйте.
источник
C #, 57 байт
Анонимная функция, которая возвращает целое число от 0 до n включительно.
Чем меньше введенное число, тем дольше время для возврата случайного значения.
Полная программа:
источник
Next
не является статичным.Bash + coreutils, 20 байтов
Golfed
seq 0 $ 1 | shuf | sed 1q
Шуф будет использовать следующий код : для генерации перестановок:
который заканчивается в
randint_genmax
который, в свою очередь, будет считывать несколько байтов случайных данных из низкоуровневого источника случайности:
то есть на низком уровне нет прямой зависимости между
shuf
входным значением и данными, считанными из источника случайности (кроме вычисления требуемой емкости байтового буфера).источник
jot will arrange for all the values in the range to appear in the output with an equal probability
(это, вероятно, граница, но все же).SmileBASIC, 38 байт
Генерирует случайные числа до тех пор, пока не получит то, которое меньше входного.
источник
Рубин,
23 15 23 3229 байтКак это работает:
1while [...];
выполняет оператор хотя бы один раз:1
прежде чемwhile
действует как nopисточник
Ом, 26 байт
Объяснение:
источник
Идти,
6361 байтИспользуйте это так:
Проверьте это в прямом эфире на игровой площадке
источник
Голанг,
847871 байтПростая отбраковка выборки.
Примечание: так как математическое / рандовое начальное число является константой 1, вызывающий должен задавать, если не требуется постоянный результат.
Тест: https://play.golang.org/p/FBB4LKXo1rБольше не тестируется практически на 64-битной системе, поскольку он возвращает 64-битную случайность и использует тестирование на отклонение.источник
import."math/rand"
тоInt31
доступно в глобальном пространстве имен, и вы можете сохранить 4 байта, такжеint
гарантированно не менее 32 бит, что сэкономит вам еще 6 байтов:=
синтаксис для еще 3 байтовInt()
import