Rand5 () - Rand7 () [закрыто]


29

Вам предоставляется функция Rand5 (). Эта функция возвращает совершенно случайные (равное распределение) целые числа от 1 до 5.

Предоставьте функцию Rand7 (), которая использует Rand5 () для получения совершенно случайных целых чисел от 1 до 7.



8
Обязательный xkcd: xkcd.com/221
Стивен Румбальски

1 и 5 включительно? то есть из набора {1,2,3,4,5}?
Аарон МакДейд

1
По каким критериям определяется один победитель?
Кодзиро

Тот момент, когда вы понимаете, что это на самом деле старый вопрос.
nyuszika7h

Ответы:


11

Ява - 61 символ

int rand7(){int s=0,c=7;while(c-->0)s+=rand5();return s%7+1;}

Тестовый драйвер для проверки:

class Rand {

    public static void main(String[] args) {
        int[] nums = new int[7];
        // get a lot of numbers
        for(int i = 0; i < 10000000; i++) nums[rand7()-1]++;
        // print the results
        for(int i = 0; i < 7; i++) System.out.println((i+1) + ": " + nums[i]);
    }

    // just for rand5()
    static java.util.Random r = new java.util.Random();

    static int rand5() {
        return r.nextInt(5)+1; // Random.nextInt(n) returns 0..n-1, so add 1
    }

    static int rand7(){int s=0,c=7;while(c-->0)s+=rand5();return s%7+1;}

}

Полученные результаты

C:\Documents and Settings\glowcoder\My Documents>java Rand
1: 1429828
2: 1429347
3: 1428328
4: 1426486
5: 1426784
6: 1429853
7: 1429374

C:\Documents and Settings\glowcoder\My Documents>

10
Дополнительные баллы за «идет к оператору»
Стив П

побрить чарса? int rand7 () {for (int s = 0, c = 7; c -> 0; s + = rand5 ()); вернуть s% 7 + 1;}
Рон

3
Этот ответ не верен: вероятности того, что эта функция вернет значения от 1 до 7, равны 0,1430656, 0,1430016, 0,1428224, 0,1426432, 0,1426432, 0,1428224 и 0,1430016 соответственно. Да, разница между минимальной и максимальной вероятностями составляет менее 0,0005, но все же в вопросе указываются «совершенно случайные целые числа».
Ильмари Каронен

@ilmari Вы правы - я только что провел тест, и похоже, что дистрибутив даже не ... позвольте мне подумать над этим
corsiKa

1
@userunknown: Да, вероятности, которые я разместил, на самом деле не являются приближениями, они точны (0,1430656 = 11177/78125 и т. д.), предполагая, что они абсолютно случайны rand5. Я вычислил их в Maple, используя простую матричную алгебру, но вы можете сделать это карандашом и бумагой за несколько минут, если хотите. Так или иначе, оказывается, что Омар уже опубликовал те же цифры (без нормализующего фактора) в комментарии к другому ответу пару дней назад. (Также, вы можете @ уведомить только одного пользователя за комментарий, хотя автор сообщения всегда уведомляется.)
Ilmari Karonen

7

Perl - 47 (было 52) символов

sub rand7{($x=5*&rand5+&rand5-3)<24?int($x/3):&rand7} 

Плюс я использую троичный оператор И рекурсию. Самый лучший день!

ОК, 47 символов, если вы используете мод вместо div:

sub rand7{($x=5*&rand5+&rand5)<27?$x%7+1:&rand7} 

Так близко ... замените 30 на 27 (= 6 + 21), и вы получите идеально равномерное распределение. О, и вы можете опустить последние два &знака, чтобы уменьшить его до 46 символов (включая пробел, в котором ваша текущая версия равна 48).
Ильмари Каронен

7

JavaScript, 42

Rand7=f=_=>(x=Rand5()+Rand5()*5-5)>7?f():x

Бонус ES5 вещь:

Rand7=eval.bind(0,'for(;x=Rand5()+Rand5()*5-5,x>7;);x')

6

Ruby - 54 символа (на основе решения Дэна МакГрата с использованием цикла)

def rand7;x=8;while x>7 do x=rand5+5*rand5-5 end;x;end

Рубин - 45 символов (то же решение, с использованием рекурсии)

def rand7;x=rand5+5*rand5-5;x>7 ?rand7: x;end

Можно сократить на 1 символ с помощью (x=rand5+5*rand5-5)>7?.
Ларс Хаугсет


4

В Common Lisp 70 персонажей:

(defun rand7()(let((n(-(+(rand5)(* 5(rand5)))5)))(if(> n 7)(rand7)n)))

Скобки занимают больше места, чем хотелось бы.


Ницца. Вы можете выжать еще два символа, указав глобальную переменную:(defun rand7()(setq n(-(+(rand5)(* 5(rand5)))5))(if(> n 7)(rand7)n))
Dr. Pain

Еще лучше:(defun rand7()(if(>(setq n(-(+(rand5)(* 5(rand5)))5))7)(rand7)n))
Доктор Пейн

4

В c / c ++ используется выборка отклонения

int rand7(){int x=8;while(x>7)x=rand5()+5*rand5()-5;return x;}

62 персонажа.


@barrycarter: условие while(x>7)так, что оно будет удовлетворяться только числами в допустимом диапазоне.
mellamokb

Виноват. Удалил мой тупой комментарий.
Баррикартер

@ Барри А потом ты оставил еще один. ;)
Матин Улхак

Мне потребовалось несколько минут, чтобы понять, как математика здесь дает равномерно случайное распределение, которое можно использовать для выборки отклонения.
Даниэль

3

Перевод на PHP, из ответа выложил Дэн МакГрат.

function Rand7(){$x=8;while($x>7)$x=rand5()+5*rand5()-5;return $x;}

67 символов.


Не должно ли это быть префиксом слова «функция» (и пробел)?
Jtjacques

Да ... и теперь это 67 символов ...
Марк-Франсуа

3

R, 34 символа

В R (язык, построенный для статистических вычислений), преднамеренно обманчивое решение:

# Construct a Rand5 function
Rand5 <- function() sample(seq(5),1)
# And the golf
Rand7=function(r=Rand5())sample(1:(r/r+6),1)
# Or (same character count)
Rand7=function(r=Rand5())sample.int(r/r+6,1)
# Or even shorter(thanks to @Spacedman)
Rand7=function()sample(7)[Rand5()]

Благодаря ленивой оценке аргументов я исключил точку с запятой и скобки.

Вывод более 10 ^ 6 копий:

> test <- replicate(10^6,Rand7())
> table(test)
test
     1      2      3      4      5      6      7 
142987 142547 143133 142719 142897 142869 142848 

library(ggplot2)
qplot(test)

гистограмма результатов


2
Если вы собираетесь быть мошенником, вы можете быть лучшим мошенником, которым вы можете быть:Rand7=function(){r=Rand5();sample(7)[r]}
Spacedman

Если вы собираетесь это сделать, зачем использовать промежуточное хранилище? Rand7=function(){sample(7)[Rand5()]}
Брайан Диггс

@BrianDiggs Путь-зависимость в действии .... :-)
Ари Б. Фридман

3

Скала, 47, 40 59 символов:

def rand7:Int={val r=5*(rand5-1)+rand5
if(r<8)r else rand7}

с 2 входами от rand5:

\ 1 2 3 4 5 
1 1 2 3 4 5  
2 6 7 8 ..
3 11 ..
4 ..
5

Я умножаю первое-1 на 5 и добавляю второе. Большинство результатов игнорируются и приводят к новым расчетам. Результат должен быть равным распределением значений от 1-25, из которого я выбираю только первые 7. Я мог бы принять первые 21 с построением по модулю, но это привело бы к более длинному коду.

исторический кодекс, который провалился, но не очень очевидно. Спасибо Ильмари Каронену за указание на это:

def rand7=(1 to 7).map(_=>rand5).sum%7+1

Спасибо Yoshiteru Takeshita, за этот подход scala-2.8.0, который сделал «сумму» такой простой. Мое решение раньше:

def rand7=((0/:(1 to 7))((a,_)=>a+rand5-1))%7+1

rand5:

val rnd = util.Random 
def rand5 = rnd.nextInt (5) + 1


Пользователь Yoshiteru Takeshita предложил сокращение до 40 символов для Scala 2.8.0 или более поздней версииdef rand7=(1 to 7).map(_=>rand5).sum%7+1
Питер Тейлор

Это решение также не является правильным, см. Комментарии к ответу свечения .
Ильмари Каронен

@IlmariKaronen: Вы правы - я переработал свое решение.
неизвестный пользователь

3

C ++

int Rand4()
{
    int r = Rand5();
    return r > 4 ? Rand4() : r;
}

inline int Rand8()
{    
    return (Rand4() - 1) << 2 + Rand4();
}

int Rand7()
{
    int r = Rand8();
    return r > 7 ? Rand7() : r;
}

С ++ (109)

Golfed

int Rand4(){int r=Rand5();return r>4?Rand4():r;}int Rand7(){int r=Rand4()-1<<2+Rand4();return r>7?Rand7():r;}

Я действительно не думаю, что вы можете назвать это «одной строкой», потому что точки с запятой определяют строку кода в C ++.
Питер Олсон

@ Питер О, ну, это даже не требует однострочников.
Матин Улхак,

Он вернул число от 1 до 8.
jimmy23013

2

Перевод в Javascript, из ответа, опубликованного Дэном МакГрат.

function Rand7(){x=8;while(x>7)x=rand5()+5*rand5()-5;return x}

62 символа


1
function Rand7(){for(x=8;x>7;x=rand5()+5*rand5()-5);return x}немного короче: P
JiminP

2

JavaScript, 85

function Rand7(){for(x=0,i=1;i<8;x^=i*((k=Rand5())%2),i*=1+(k<5));return x?x:Rand7()}

Я знаю, что есть более короткий ответ, но я хотел показать тест этой головоломки. Оказывается, что только ответ Клайда Лобо, использующий выборку отклонения Дэна Макгрэта, является правильным (между ответами JS).


2

С ++

int Rand7()
{
    int r = Rand5();
    int n = 5;
    do {
        r = (r - 1) * 5 + Rand5();
        int m = n * 5 / 7 * 7;
        if (r <= m) {
            return r % 7 + 1;
        }
        r -= m;
        n = n * 5 - m;
    } while (1);
}

Распределение чисел (1000000 целых чисел):

142935 142751 142652 143299 142969 142691 142703

Среднее количество вызовов Rand5 () на каждое сгенерированное целое число составляет около 2,2 (от 2 до 10+).

1 2      3      4     5    6   7 8  9 10
0 840180 112222 44433 2212 886 0 60 6 1

2

В Java (или C / C ++, я полагаю)

  • используя формулу генерации Александру, в 65 символов:

    int rand7(){int x=rand5()*5+rand5()-6;return x>20?rand7():x/3+1;}
    
  • используя формулу генерации Дэна МакГрата, в 60 символов

    int rand7(){int x=rand5()+5*rand5()-5;return x>7?rand7():x;}
    

1

Clojure - 58 символов

(defn rand7[](#(if(<% 8)%(rand7))(+(rand5)(*(rand5)5)-5)))

1

Питон, 56 37 символов

Другое решение, которое может быть неправильным, в Python:

rand7 = lambda: sum(rand5() for i in range(7)) % 7 + 1

Это кажется слишком простым, но когда я пытаюсь:

counter = [0] * 7
for i in range(100000):
     counter[rand7()] += 1

Я получаю достаточно равномерное распределение (все между 14000 и 14500).

Хорошо, теперь, когда кто-то голосовал за этот пост: действительно ли это решение правильно? Я более опубликовал это здесь, чтобы люди критиковали это. Ну, если это правильно, моя версия для гольфа будет:

rand7=lambda:eval("+rand5()"*7)%7+1

который выходит на 37 символов.


Ваше решение не является правильным: вы основываете свое решение на 7 бросках честного 5-стороннего кубика, что означает, что есть 5 ^ 7 (от 5 до 7 степени) равноправных результатов. Так как это не кратно 7, вы не можете вернуть 7 равновероятных результатов. Я не думаю, что есть простая формула для того, что вы возвращаете; Вы можете перебрать расчет или выполнить его вручную на меньших числах (подбросьте 3 монеты (H = 1, T = 2) и суммируйте результаты).
Жиль "ТАК - перестань быть злым"

1
Вау, распределение, которое вы генерируете, хотя и не является равномерным, удивительно близко: точная пропорция вероятностей каждого числа равна {1: 11177, 2: 11172, 3: 11158, 4: 11144, 5: 11144, 6: 11158, 7: 11172}
Омар



1

Perl, 43 символа, итеративная выборка отклонения

sub rand7{1while($_=5*&rand5-rand5)>6;$_+1}

Это дает предупреждение Ambiguous use of -rand5 resolved as -&rand5(), но работает правильно. При добавлении &также ко второму rand5вызову это исправляется за счет одного удара. (И наоборот, другой &также может быть удален, если rand5 он был определен с() прототипа.)

Ps. Следующая версия из 46 символов примерно в три раза быстрее:

sub rand7{1while($_=5*&rand5-rand5)>20;$_%7+1}

1

Java - 66 символов

int rand7(){int s;while((s=rand5()*5+rand5())<10);return(s%7+1);}

Дольше, чем предыдущая процедура, но я думаю, что она возвращает равномерно распределенные числа за меньшее время.


1

PostScript (46)

Это использует двоичную кодировку токена, поэтому вот hexdump:

00000000  2f 72 61 6e 64 37 7b 38  7b 92 38 37 92 61 7b 92  |/rand7{8{.87.a{.|
00000010  40 7d 69 66 92 75 32 7b  72 61 6e 64 35 7d 92 83  |@}if.u2{rand5}..|
00000020  35 92 6c 92 01 35 92 a9  7d 92 65 7d 92 33        |5.l..5..}.e}.3|
0000002e

Чтобы попробовать это, вы также можете скачать его .

Вот код без комментариев и комментариев, а также тестовый код.

% This is the actual rand7 procedure.
/rand7{
  8{                      % potentialResult
    % only if the random number is less than or equal to 7, we're done
    dup 7 le{             % result
      exit                % result
    }if                   % potentialResult
    pop                   % -/-
    2{rand5}repeat        % randomNumber1 randomNumber2
    5 mul add 5 sub       % randomNumber1 + 5*randomNumber2 - 5 = potentialResult
  }loop
}def

%Now, some testing code.

% For testing, we use the built-in rand operator; 
% Doesn't really give a 100% even distribution as it returns numbers
% from 0 to 2^31-1, which is of course not divisible by 5.
/rand5 {
  rand 5 mod 1 add
}def

% For testing, we initialize a dict that counts the number of times any number
% has been returned. Of course, we start the count at 0 for every number.
<<1 1 7{0}for>>begin

% Now we're calling the function quite a number of times 
% and increment the counters accordingly.
1000000 {
  rand7 dup load 1 add def
}repeat

% Print the results
currentdict{
  2 array astore ==
}forall

-1
int result = 0;

for (int i = 0; i++; i<7)
    if (((rand(5) + rand(5)) % 2) //check if odd
        result += 1;

return result + 1;

2
Это не даст равномерного распределения. Посмотрите на распределение rand (5) + rand (5) более 10000 итераций, чтобы понять, почему
gnibbler

Результатом может быть любое число от 1 до 8 в вашем коде ...
Омар

Плюс, как сказал Гнибблер, распределение не является равномерным: (rand (5) + rand (5))% 2 смещено в сторону 0, оно выдает 0 13 раз за каждые 12 раз, когда оно выдает 1; вероятности пропорциональны {0: 13, 1: 12}. В этой записи обозначения для вашей функции пропорциональны {1: 62748517, 2: 405451956, 3: 1122790032, 4: 1727369280, 5: 1594494720, 6: 883104768, 7: 271724544, 8: 35831808} (довольно сильно наклонены в сторону большие цифры). Или, исправляя цикл для запуска 6 раз, {1: 4826809, 2: 26733096, 3: 61691760, 4: 75928320, 5: 52565760, 6: 19408896, 7: 2985984}
Омар

-1

R (30 символов)

Определите rand7:

rand7=function(n)sample(7,n,T)

Поскольку R был написан с учетом статистического анализа, эта задача тривиальна, и я использую встроенную функцию sample с заменой, установленной на TRUE.

Образец вывода:

> rand7(20)
 [1] 4 3 6 1 2 4 3 2 3 2 5 1 4 6 4 2 4 6 6 1
> rand7(20)
 [1] 1 2 5 2 6 4 6 1 7 1 1 3 7 6 4 7 4 2 1 2
> rand7(20)
 [1] 6 7 1 3 3 1 5 4 3 4 2 1 5 4 4 4 7 7 1 5

1
Это говорит о том, что вы должны использовать Rand5. Не говорит как, но вы должны использовать это ...
Spacedman

@Spacedman Да, я явно проигнорировал это. Это использование по не-ссылке.
Андри

-1

Groovy

rand7={if(b==null)b=rand5();(b=(rand5()+b)%7+1)}

Пример распределения по 35 000 итераций:

[1:5030, 2:4909, 3:5017, 4:4942, 5:5118, 6:4956, 7:5028]

Это плохо, что это с состоянием?



-1

Как насчет этого?

int Rand7()
{
    return Rand5()+ Rand5()/2;
}

Каким бы ни был язык, его /оператор выполняет целочисленную математику? Что происходит с вашими результатами, если он выполняет десятичную, с плавающей или целочисленную математику?
Кодзиро

Предполагая , целочисленное деление, эта функция имеет следующее распределение: [2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25]. Не совсем равномерно.
Прим

Примо правильно. добавление случайных чисел, как правило, приводит к перекосу вероятностей к средним значениям.
gnibbler

-1

Ява - 54

int m=0;int rand7(){return(m=m*5&-1>>>1|rand5())%7+1;}

Распределительный тест: [1000915, 999689, 999169, 998227, 1001653, 1000419, 999928]

Алгоритм:

  • Держите глобальную переменную
  • умножьте на 5, чтобы получить 5 свободных мест в самом младшем конце
  • Обрежьте бит знака, чтобы сделать его положительным (необязательно, если поддерживаются числа без знака)
  • По модулю 7 ответ

> Числа больше не взаимно коррелированы, а индивидуально совершенно случайны.


-1

Рубин (43 байта)

def rand7;(0..7).reduce{|i|i+rand5}%7+1;end

Решение cemper93, портированное на Ruby, на три байта короче;) (34 байта)

def rand7;eval("+rand5"*7)%7+1;end

-3

Код C / C ++, основной код имеет только одну строку!

static unsigned int gi = 0;

int rand7()
{
    return (((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1;
}

//call this seed before rand7
//maybe it's not best seed, if yo have any good idea tell me please
//and thanks JiminP again, he remind me to do this
void srand7()
{
    int i, n = time(0);
    for (i = 0; i < n % 7; i++)
        rand7();
}

Srand7 () - это семя rand7, оно должно вызывать эту функцию перед rand7, точно так же, как вызывать srand перед rand в C.

Это очень хороший вариант, потому что он вызывает rand () только один раз, и никакой цикличности, никакой дополнительной памяти не тратится.

Позвольте мне объяснить это: рассмотрим целочисленный массив размером 5:

1st get one number from 1 2 3 4 5 by rand5
2nd get one number from 2 3 4 5 6
3rd get one number from 3 4 5 6 7
4th get one number from 4 5 6 7 1
5th get one number from 5 6 7 1 2
5th get one number from 6 7 1 2 3
7th get one number from 7 1 2 3 4

Итак, мы получили ТАБЛИЦУ, каждая из 1-7 встречается в ней 5 раз и имеет все 35 чисел, поэтому вероятность каждого числа составляет 5/35 = 1/7. И в следующий раз

8th get one number from 1 2 3 4 5
9th get one number from 2 3 4 5 6
......

После достаточного количества раз мы можем получить равномерное распределение 1-7.

Таким образом, мы можем выделить массив для восстановления пяти элементов 1-7 по loop-left-shift и каждый раз получать одно число из массива по rand5. Вместо этого мы можем сгенерировать все семь массивов и использовать их циклически. Код также прост, имеет много коротких кодов, способных сделать это.

Но мы можем использовать свойства операции%, поэтому строки таблицы 1-7 эквивалентны (rand5 + i)% 7, то есть: a = rand ()% 5 + 1 - это rand5 на языке C, b = gi ++ % 7 генерирует все перестановки в таблице выше, а 0 - 6 заменяют 1 - 7 c = (a + b)% 7 + 1, генерируют 1 - 7 равномерно. Наконец, мы получили этот код:

(((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1 

Но мы не можем получить 6 и 7 при первом вызове, поэтому нам нужно начальное число, например srand for rand в C / C ++, чтобы дезорганизовать перестановку для первого формального вызова.

Вот полный код для тестирования:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static unsigned int gi = 0;

//a = rand() % 5 + 1 is rand5 in C language,
//b = gi++ % 7 generates all permutations,
//c = (a + b) % 7 + 1, generates 1 - 7 uniformly.
//Dont forget call srand7 before rand7
int rand7()
{
   return (((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1;
}

//call this seed before rand7
//maybe it's not best seed, if yo have any good idea tell me please
//and thanks JiminP again, he remind me to do this
void srand7()
{
    int i, n = time(0);
    for (i = 0; i < n % 7; i++)
        rand7();
}

void main(void)
{
    unsigned int result[10] = {0};
    int k;

    srand((unsigned int)time(0)); //initialize the seed for rand
    srand7() //initialize the rand7

    for (k = 0; k < 100000; k++)
        result[rand7() - 1]++;

    for (k = 0; k < 7; k++)
        printf("%d : %.05f\n", k + 1, (float)result[k]/100000);
}

Он «проходит» «тест», но это не значит, что это хорошая случайная функция. Могу ли я получить 6или 7позвонив один раз ?
JiminP

Но есть хорошие и плохие виды приближения. И этот код плохой - потому что он не дает равномерного распределения при вызове только один раз. Если кто-то написал что-то вроде int main(){if(rand7()==6) printf("Hello, world!");}, аппроксимация с использованием цикла выведет «Hello, world!» 1 в 7 раз, но ваш код не.
JiminP

спасибо @JiminP! Вы правы на 6,7 в первый раз. мне нужно семя, чтобы дезорганизовать перед вызовом rand7, семя, как и srand в C / C ++. я исправил свой код и еще раз спасибо !!!
Шон

хм .... сранд10 не работает, последние 3 номера не могут попасть на 10, 20, 30 ... позиции. извините @JiminP, но как его изменить? Я думаю, что это надежный способ.
Шон

2
Различные вызовы этой функции не зависят друг от друга. Спецификация здесь не требует этого, но это, как правило, исключение генераторов случайных чисел. В противном случае вы могли бы сказать, что возвращайте случайное равномерное число в первый раз, а в будущих вызовах просто верните (предыдущий + 1)% 7 ...
Омар
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.