Вам надана функція Rand5 (). Ця функція повертає цілком випадкові цілі числа (однаковий розподіл) між 1 і 5.
Надайте функцію Rand7 (), яка використовує Rand5 () для отримання ідеально випадкових цілих чисел між 1 і 7.
Вам надана функція Rand5 (). Ця функція повертає цілком випадкові цілі числа (однаковий розподіл) між 1 і 5.
Надайте функцію Rand7 (), яка використовує Rand5 () для отримання ідеально випадкових цілих чисел між 1 і 7.
Відповіді:
Ява - 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>
rand5
. Я обчислював їх у Maple, використовуючи просту матричну алгебру, але ви можете зробити це олівцем і папером за кілька хвилин, якщо хочете. У будь-якому випадку, виявляється, Омар вже розмістив ті ж цифри (коефіцієнт нормування коефіцієнта) в коментарі до іншої відповіді на пару днів раніше. (Також ps., Ви можете лише попередити одного користувача за коментар, хоча автор публікації завжди повідомляється про це в будь-якому випадку.)
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}
&
знаки, щоб зменшити його до 46 символів (включаючи пробіл, який ставить вашій поточній версії 48).
Ruby - 54 символи (на основі рішення Дена Макграта, використовуючи цикл)
def rand7;x=8;while x>7 do x=rand5+5*rand5-5 end;x;end
Ruby - 45 символів (той же розчин, використовуючи рекурсію)
def rand7;x=rand5+5*rand5-5;x>7 ?rand7: x;end
(x=rand5+5*rand5-5)>7?
.
На Python:
def Rand7():
while True:
x = (Rand5() - 1) * 5 + (Rand5() - 1)
if x < 21: return x/3 + 1
У загальному 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))
(defun rand7()(if(>(setq n(-(+(rand5)(* 5(rand5)))5))7)(rand7)n))
В c / c ++ з використанням відбору відторгнення
int rand7(){int x=8;while(x>7)x=rand5()+5*rand5()-5;return x;}
62 символи.
while(x>7)
, щоб її задовольняли лише числа у дійсному діапазоні.
Переклад на PHP, з відповіді, опублікованої Деном МакГратом.
function Rand7(){$x=8;while($x>7)$x=rand5()+5*rand5()-5;return $x;}
67 символів.
У 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)
Rand7=function(){r=Rand5();sample(7)[r]}
Rand7=function(){sample(7)[Rand5()]}
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
Дякую Йошитеру Такешиті, за цей підхід, який набув масштабу-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
def rand7=(1 to 7).map(_=>rand5).sum%7+1
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;
}
int Rand4(){int r=Rand5();return r>4?Rand4():r;}int Rand7(){int r=Rand4()-1<<2+Rand4();return r>7?Rand7():r;}
Переклад на Javascript, з відповіді, опублікованої Деном МакГратом.
function Rand7(){x=8;while(x>7)x=rand5()+5*rand5()-5;return x}
62 символи
function Rand7(){for(x=8;x>7;x=rand5()+5*rand5()-5);return x}
трохи коротше: P
function Rand7(){for(x=0,i=1;i<8;x^=i*((k=Rand5())%2),i*=1+(k<5));return x?x:Rand7()}
Я знаю, що відповідь коротша, але я хотів показати тест цієї головоломки. Виявляється, лише відповідь Клайда Лобо з використанням вибірки відхилення Дена МакГрата є правильною (між відповідями JS).
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
У 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;}
Ще одне рішення, яке може бути неправильним, в 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 знаків.
Ява, 65 символів:
int rand7(){int r;do{r=rand5()+5*rand5()-5;}while(r>7);return r;}
def rand7():
while True:
n=5*(rand5()-1)+(rand5()-1)
if n<21:return n%7+1
але цілком правильне, виходячи з тут міркувань .
sub rand7{1while($_=5*&rand5-rand5)>6;$_+1}
Це дає попередження про Ambiguous use of -rand5 resolved as -&rand5()
, але працює правильно. Попередження &
до другого rand5
дзвінка фіксує його ціною одного удару. (І навпаки, інше &
також можна видалити, якщо rand5
воно було визначено ()
прототипом.)
Пс. Наступна 46-char версія приблизно втричі швидша:
sub rand7{1while($_=5*&rand5-rand5)>20;$_%7+1}
int rand7(){int s;while((s=rand5()*5+rand5())<10);return(s%7+1);}
Більше, ніж попередня програма, але я думаю, що ця повертає рівномірно розподілені числа за менший час.
PostScript (46)
Тут використовується кодування двійкового маркера, отже, ось шістнадцятковий:
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
int result = 0;
for (int i = 0; i++; i<7)
if (((rand(5) + rand(5)) % 2) //check if odd
result += 1;
return result + 1;
Визначте 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
Rand7=Rand5[]~Sum~{7}~Mod~7+1&
Як щодо цього?
int Rand7()
{
return Rand5()+ Rand5()/2;
}
/
оператор цілочисельну математику? Що станеться з вашими результатами, якщо це робить математика з десятковою, крапкою чи цілим числом?
[2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25]
. Не зовсім рівномірно.
int m=0;int rand7(){return(m=m*5&-1>>>1|rand5())%7+1;}
Тест на розповсюдження:
[1000915, 999689, 999169, 998227, 1001653, 1000419, 999928]
Алгоритм:
> Цифри вже взаємно не співвідносяться, а індивідуально абсолютно випадкові.
Код 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 за допомогою циклу-зсуву вліво і отримувати одне число з масиву кожен раз за допомогою 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 для 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
зателефонувавши один раз ?
int main(){if(rand7()==6) printf("Hello, world!");}
, наближення за допомогою циклу надрукує "Привіт, світ!" 1 раз у 7 разів, але ваш код - ні.