Я думаю, у меня есть четыре ответа, два из которых дают точные решения , как у @Adam Rosenfield , но без проблемы бесконечного цикла, и два других с почти идеальным решением, но более быстрой реализацией, чем первый.
Лучшее точное решение требует 7 звонков на rand5
, но давайте продолжим, чтобы понять.
Метод 1 - Точный
Сила ответа Адама в том, что он дает идеальное равномерное распределение, и существует очень высокая вероятность (21/25), что потребуется только два вызова rand5 (). Однако в худшем случае это бесконечный цикл.
Первое решение, приведенное ниже, также обеспечивает идеальное равномерное распределение, но требует всего 42 вызовов на rand5
. Нет бесконечных циклов.
Вот реализация R:
rand5 <- function() sample(1:5,1)
rand7 <- function() (sum(sapply(0:6, function(i) i + rand5() + rand5()*2 + rand5()*3 + rand5()*4 + rand5()*5 + rand5()*6)) %% 7) + 1
Для людей, не знакомых с R, вот упрощенная версия:
rand7 = function(){
r = 0
for(i in 0:6){
r = r + i + rand5() + rand5()*2 + rand5()*3 + rand5()*4 + rand5()*5 + rand5()*6
}
return r %% 7 + 1
}
Распределение rand5
будет сохранено. Если мы посчитаем, каждая из 7 итераций цикла имеет 5 ^ 6 возможных комбинаций, таким образом, общее количество возможных комбинаций равно (7 * 5^6) %% 7 = 0
. Таким образом, мы можем разделить случайные числа, сгенерированные на равные группы по 7. Более подробное обсуждение см. Во втором методе.
Вот все возможные комбинации:
table(apply(expand.grid(c(outer(1:5,0:6,"+")),(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
15625 15625 15625 15625 15625 15625 15625
Я думаю, прямо сейчас показать, что метод Адама будет работать намного быстрее. Вероятность того, что в решении Адама есть 42 или более вызовов rand5
, очень мала ((4/25)^21 ~ 10^(-17)
).
Метод 2 - не точно
Теперь второй метод, который почти одинаков, но требует 6 вызовов rand5
:
rand7 <- function() (sum(sapply(1:6,function(i) i*rand5())) %% 7) + 1
Вот упрощенная версия:
rand7 = function(){
r = 0
for(i in 1:6){
r = r + i*rand5()
}
return r %% 7 + 1
}
Это, по сути, одна итерация метода 1. Если мы сгенерируем все возможные комбинации, вот результат подсчета:
table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
2233 2232 2232 2232 2232 2232 2232
Один номер снова появится в 5^6 = 15625
испытаниях.
Теперь, в методе 1, добавив от 1 до 6, мы перемещаем число 2233 в каждую последующую точку. Таким образом, общее количество комбинаций будет совпадать. Это работает, потому что 5 ^ 6 %% 7 = 1, а затем мы делаем 7 подходящих вариантов, поэтому (7 * 5 ^ 6 %% 7 = 0).
Метод 3 - Точный
Если аргумент метода 1 и 2 понятен, метод 3 следует и требует только 7 вызовов rand5
. На данный момент, я чувствую, что это минимальное количество вызовов, необходимое для точного решения.
Вот реализация R:
rand5 <- function() sample(1:5,1)
rand7 <- function() (sum(sapply(1:7, function(i) i * rand5())) %% 7) + 1
Для людей, не знакомых с R, вот упрощенная версия:
rand7 = function(){
r = 0
for(i in 1:7){
r = r + i * rand5()
}
return r %% 7 + 1
}
Распределение rand5
будет сохранено. Если мы посчитаем, у каждой из 7 итераций цикла будет 5 возможных результатов, таким образом, общее количество возможных комбинаций будет (7 * 5) %% 7 = 0
. Таким образом, мы можем разделить случайные числа, сгенерированные на равные группы по 7. Для более подробного обсуждения см. Метод один и два.
Вот все возможные комбинации:
table(apply(expand.grid(0:6,(1:5)),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
5 5 5 5 5 5 5
Я думаю, прямо сейчас показать, что метод Адама все еще будет работать быстрее. Вероятность того, что в решении Адама будет 7 или более вызовов rand5
, все еще мала ((4/25)^3 ~ 0.004
).
Метод 4 - не точно
Это незначительная вариация второго метода. Он почти равномерный, но требует 7 вызовов rand5
, то есть одного дополнительного к методу 2:
rand7 <- function() (rand5() + sum(sapply(1:6,function(i) i*rand5())) %% 7) + 1
Вот упрощенная версия:
rand7 = function(){
r = 0
for(i in 1:6){
r = r + i*rand5()
}
return (r+rand5()) %% 7 + 1
}
Если мы сгенерируем все возможные комбинации, вот результирующие значения:
table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6,1:5),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
11160 11161 11161 11161 11161 11161 11160
Два числа появятся еще раз в 5^7 = 78125
испытаниях. В большинстве случаев я могу жить с этим.