Cлучайное число от 1 до 10
Как написать функцию, которая возвращает случайное число от 1 до 10,используя генератор случайных чисел, ограниченный диапазоном от 1 до 5? В принципе подойдёт любой язык, мне главное идеи.
Ответы (5 шт):
Если вам надо получить число от 1 до 10, генерируя числа в пределах от 1 до 5, то просто умножайте исходное число на 2 случайным образом:
Python
import random
num = random.randint(1,5)
double = random.randint(1,2)
print(double * num)
UPD
Если нельзя генерировать число от 1 до 2, то чтобы решить умножать или нет, то генерируем еще одно число от 1 до 5, если оно больше или равно 3, то умножаем на 2, иначе - нет. Тут правда с вероятностью 3/5 - будет умножать, 2/5 - не будет.
import random
num = random.randint(1,5)
double = 2 if random.randint(1,5) >=3 else 1
print(double * num)
Можно использовать сделать еще более псевдослучайную генерацию, привяжемся ко времени, если абсолютное время четное, то умножаем, иначе - нет.
Правда вроде генератор случайных числе тоже как-то привязан ко времени, не знаю какой это окажет эффект
import random
from datetime import datetime
num = random.randint(1,5)
double = 2 if datetime.now().microsecond % 2 == 0 else 1
print(double * num)
Правда у всех решений выше есть один важный недостаток, таким способом нельзя получить ни 7, ни 9. Спасибо @andreymel за наблюдение.
Можно ничего не умножать, а сгенерировать 2 числа и сложить случайным образом.
import random
from datetime import datetime
num = random.randint(1,5)
if datetime.now().microsecond % 2 == 0:
print(num + random.randint(1,5))
else:
print(num)
Считая, что генератор равномерный и нужно равномерное же распределение:
Получаем случайное число, пока оно не станет равным 1,2,4 или 5.
Получаем второе случайное число.
Если первое - 1 или 2, возвращаем второе; если 4 или 5 - второе, увеличенное на 5.
r() - ваш генератор от 1 до 5.
Генератор от 1 до 10:
int v() {
int k;
for(k = r(); k == 3; k = r());
if (k < 3) return r(); else return 5+r();
}
Проверка - https://ideone.com/6m47cs
Возможно, такой ответ уже дали, но не пропадать же добру.
P.S. Да, по сути у меня ответ совпадает с ответом Harry, долго я код писал.
P.P.S. В конце добавил ещё один годный вариант, которого вроде бы не было ещё в комментариях.
import random
import seaborn as sns
import matplotlib.pylab as plt
def random1_5():
return random.randint(1,5)
def random1_10():
while True:
x = random1_5()
if x <= 2:
return random1_5()
elif x <= 4:
return random1_5() + 5
n = 1000
y = [random1_10() for _ in range(n)]
sns.countplot(y)
plt.title('random(1,5) -> random(1,10)')
y1 = [random.randint(1,10) for _ in range(n)]
plt.figure()
sns.countplot(y1)
plt.title('random(1,10)')
Кидаем кубик 1-5 первый раз, чтобы выбрать диапазон:
- если выпадает 1 или 2, то следующее кидание кубика выдаём как есть
- если выпадет 3 или 4, то выдаём следующее кидание кубика + 5
- если выпадает 5, то кидаем кубик заново
Проверим распределение такого генератора:
Для сравнения распределение встроенного random от 1 до 10:
Если запускать код несколько раз, то видно, что распределение выходит вполне равномерное, хотя и сдвигается туда-сюда. Но перекосов нет.
UPDATE:
Ради интереса проверил также вариант от Pavel Grishaev со сложением рандомов, распределение получается неравномерное:
def random1_10():
while True:
x = random1_5() + random1_5() + random1_5() - 2
if x <= 10:
return x
UPDATE2:
Вроде нашёл ещё один более-менее равномерный вариант:
def random1_10():
return sum(random1_5() for _ in range(10)) % 10 + 1
Суть: складываем результаты рандома(1,5) 10 раз, берём остаток от деления на 10 и прибавляем 1.
Интересная мысль пришла мне в бессоннице.
10 значений - это 5 пар значений. Естественным образом приходит мысль, что генератор [1, 5] дает нам номер пары. Далее требуется равновероятно выбрать, какое число из пары выдать. Т.е. к полученному ранее числу нужно прибавить 0 или 1 (50/50). А вот для этого нам генератор уже не требуется, можно прибавлять 1 и 0 поочередно.
Предлагаю расчет по следующей формуле:
r = (2 * r1_5() - 1) + fb()
Левая часть - выбор пары.
fb() - периодическая прямоугольная функция.
Тест на JavaScript:
const r1_5 = () => Math.floor(Math.random() * 5) + 1;
const fb = () => fb.v++ % 2;
fb.v = 0;
let histo = Array(12).fill(0);
for(let i = 0; i<1000000; i++)
{
let r = (2 * r1_5() - 1) + fb();
histo[r]++;
}
histo.forEach(e => console.log(e));
UPD
Я осознал, что хотя статистически распределение равномерное, сама последовательность вызывает беспокойство, потому что состоит из чередующихся четных и нечетных чисел.
Поэтому предлагаю усовершенствованный вариант, где функция fb() будет зависеть от результата генератора [1, 5], т.е. обретает черты псевдослучайности:
const r1_5 = () => Math.floor(Math.random() * 5) + 1;
const fb = (r) => (fb.v += r) % 2;
fb.v = 0;
let histo = Array(12).fill(0);
for (let i = 0; i < 1000000; i++)
{
let r0 = r1_5();
let r = (2 * r0 - 1) + fb(r0);
histo[r]++;
}
histo.forEach(e => console.log(e));
UPD2
Как правильно заметил @VladimirGamalyan, вероятности для четных/нечетных чередуются, и с таким генератором, если собрать статистику, можно играть с положительным матожиданием (вероятность угадать 60%).
Сложить 25 случайных чисел от 0 до 4, взять остаток от деления на 10, прибавить единицу:
fun random10(): Int {
var sum = 0
repeat(25) {
sum += random5() - 1
}
return sum % 10 + 1
}
Распределение для 1 000 000 случайных значений:
[0.1003, 0.0996, 0.0998, 0.0999, 0.0997, 0.1002, 0.1000, 0.1001, 0.1001, 0.1002]




