Cлучайное число от 1 до 10

Как написать функцию, которая возвращает случайное число от 1 до 10,используя генератор случайных чисел, ограниченный диапазоном от 1 до 5? В принципе подойдёт любой язык, мне главное идеи.


Ответы (5 шт):

Автор решения: Vetedde

Если вам надо получить число от 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)
→ Ссылка
Автор решения: Harry

Считая, что генератор равномерный и нужно равномерное же распределение:

Получаем случайное число, пока оно не станет равным 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

→ Ссылка
Автор решения: CrazyElf

Возможно, такой ответ уже дали, но не пропадать же добру.
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.

введите сюда описание изображения

→ Ссылка
Автор решения: Laukhin Andrey

Интересная мысль пришла мне в бессоннице.

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%).

→ Ссылка
Автор решения: Vadik

Сложить 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]

→ Ссылка