Код решения:
int rand6() {
while (true) {
int val = 4 * rand2() + 2 * rand2() + rand2();
if (val < 6) {
return 1 + val;
}
}
}Или можно заменить на битовые операции:
int rand6() {
while (true) {
int val = (rand2() << 2) | (rand2() << 1) | rand2();
if (val < 6) {
return val + 1;
}
}
}Это классическая задача на Sampling Rejection.
Аналогичные задачи:
1) Написать rand7() имея rand5()
2) Написать rand10() имея rand7()
Почему вероятность - 1/6?
4 * rand2() + 2 * rand2() + rand2() дает равномерно распределенные значения от 0 до 7 (всего 8 значений). Нам надо преобразовать это в диапазон от 1 до 6 (6 значений).
P[результат = x] = P[с первой попытки = x] + P[провал] * P[со второй попытки = x] + P[провал] * P[провал] * P[с третьей попытки = x] + ...
x от 1 до 6.
P[провал] = 2/8 = 1/4. - Вероятность, что выпадет 6 или 7 и нам нужно перейти на следующую итерацию цикла.
P[с первой попытки = x] = P[со второй попытки = x] = P[с третьей попытки = x] = ... = 1/8
Тогда:
P[результат = x] = 1/8 * (1 + 1/4 + 1/4^2 + ...1/4^n + ...) = 1/8 * 1/(1-1/4) = 1/8 * 4/3 = 1/6.
Сколько нужно попыток?
E[N] = 1 + P[провал] + P[провал] ^2 + ... = 1/(1-P[провал]) = 1/P[успеха] = 1/(6/8) = 8/6 = 4/3.
Для других задач формулы аналогичные:
1) Написать rand7() имея rand5(): 5 * rand5() + rand5(). Смотрим <21 и делим на 3.
2) Написать rand10() имея rand7(): 7 * rand7() + rand7(). Смотрим <40 и делим на 4.