Bạn được cung cấp một hàm Rand5 (). Hàm này trả về các số nguyên hoàn toàn ngẫu nhiên (phân phối bằng nhau) từ 1 đến 5.
Cung cấp hàm Rand7 (), sử dụng Rand5 () để tạo ra các số nguyên hoàn toàn ngẫu nhiên trong khoảng từ 1 đến 7.
Bạn được cung cấp một hàm Rand5 (). Hàm này trả về các số nguyên hoàn toàn ngẫu nhiên (phân phối bằng nhau) từ 1 đến 5.
Cung cấp hàm Rand7 (), sử dụng Rand5 () để tạo ra các số nguyên hoàn toàn ngẫu nhiên trong khoảng từ 1 đến 7.
Câu trả lời:
Java - 61 ký tự
int rand7(){int s=0,c=7;while(c-->0)s+=rand5();return s%7+1;}
Kiểm tra trình điều khiển để xác nhận:
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ác kết quả
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
. Tôi đã tính toán chúng trong Maple bằng cách sử dụng đại số ma trận đơn giản, nhưng bạn có thể làm điều đó bằng bút chì và giấy trong vài phút nếu bạn muốn. Dù sao, hóa ra Omar đã đăng những con số tương tự (yếu tố bình thường hóa) trong một bình luận cho một câu trả lời khác vài ngày trước đó. (Ngoài ra ps., Bạn chỉ có thể @notify một người dùng cho mỗi bình luận, mặc dù tác giả của bài đăng luôn được thông báo trong mọi trường hợp.)
sub rand7{($x=5*&rand5+&rand5-3)<24?int($x/3):&rand7}
Thêm vào đó tôi có thể sử dụng toán tử ternary VÀ đệ quy. Tốt nhất ... ngày ... bao giờ!
OK, 47 ký tự nếu bạn sử dụng mod thay vì div:
sub rand7{($x=5*&rand5+&rand5)<27?$x%7+1:&rand7}
&
dấu hiệu cuối cùng để giảm xuống 46 ký tự (bao gồm cả khoảng trắng, đặt phiên bản hiện tại của bạn ở mức 48).
Ruby - 54 ký tự (dựa trên giải pháp Dan McGrath, sử dụng vòng lặp)
def rand7;x=8;while x>7 do x=rand5+5*rand5-5 end;x;end
Ruby - 45 ký tự (cùng một giải pháp, sử dụng đệ quy)
def rand7;x=rand5+5*rand5-5;x>7 ?rand7: x;end
(x=rand5+5*rand5-5)>7?
.
Trong Common Lisp 70 ký tự:
(defun rand7()(let((n(-(+(rand5)(* 5(rand5)))5)))(if(> n 7)(rand7)n)))
Dấu ngoặc đơn chiếm nhiều không gian hơn tôi muố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))
Trong c / c ++ sử dụng lấy mẫu từ chối
int rand7(){int x=8;while(x>7)x=rand5()+5*rand5()-5;return x;}
62 ký tự.
while(x>7)
, do đó sẽ chỉ được thỏa mãn bởi các số trong phạm vi hợp lệ.
Dịch sang PHP, từ câu trả lời được đăng ny Dan McGrath.
function Rand7(){$x=8;while($x>7)$x=rand5()+5*rand5()-5;return $x;}
67 ký tự.
Trong R (một ngôn ngữ được xây dựng để tính toán thống kê), một giải pháp gian lận có chủ ý:
# 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()]
Nhờ lười đánh giá các lập luận, tôi đã loại bỏ dấu chấm phẩy và niềng răng.
Đầu ra trên 10 ^ 6 lần lặp lại:
> 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}
với 2 đầu vào từ rand5:
\ 1 2 3 4 5
1 1 2 3 4 5
2 6 7 8 ..
3 11 ..
4 ..
5
Tôi nhân số 1 với 5 và thêm số thứ hai. Hầu hết các kết quả được bỏ qua, và dẫn đến một tính toán mới. Kết quả phải là một phân phối giá trị bằng nhau từ 1-25, từ đó tôi chỉ chọn 7 giá trị đầu tiên. Tôi có thể chấp nhận 21 đầu tiên với việc xây dựng một modulo, nhưng điều này sẽ dẫn đến mã dài hơn.
mã lịch sử đã thất bại, nhưng không rõ ràng lắm. Cảm ơn Ilmari Karonen đã chỉ ra:
def rand7=(1 to 7).map(_=>rand5).sum%7+1
Cảm ơn Yoshiteru Takeshita, vì cách tiếp cận scala-2.8.0 này đã khiến cho 'tổng' trở nên dễ dàng. Giải pháp của tôi trước đây:
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;}
Dịch sang Javascript, từ câu trả lời được đăng bởi Dan McGrath.
function Rand7(){x=8;while(x>7)x=rand5()+5*rand5()-5;return x}
62 ký tự
function Rand7(){for(x=8;x>7;x=rand5()+5*rand5()-5);return x}
ngắn hơn một chút: P
function Rand7(){for(x=0,i=1;i<8;x^=i*((k=Rand5())%2),i*=1+(k<5));return x?x:Rand7()}
Tôi biết có câu trả lời ngắn hơn, nhưng tôi muốn thể hiện bài kiểm tra của câu đố này. Hóa ra chỉ có câu trả lời của Clyde Lobo khi sử dụng mẫu từ chối của Dan McGrath là chính xác (giữa các câu trả lời của 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);
}
Phân phối số (1000000 số nguyên):
142935 142751 142652 143299 142969 142691 142703
Số lượng cuộc gọi trung bình đến Rand5 () trên mỗi số nguyên được tạo là khoảng 2,2 (2 đến 10+).
1 2 3 4 5 6 7 8 9 10
0 840180 112222 44433 2212 886 0 60 6 1
Một giải pháp khác có thể sai, trong Python:
rand7 = lambda: sum(rand5() for i in range(7)) % 7 + 1
Điều này có vẻ quá đơn giản, nhưng khi tôi thử:
counter = [0] * 7
for i in range(100000):
counter[rand7()] += 1
Tôi nhận được một phân phối hợp lý thậm chí (tất cả trong khoảng từ 14000 đến 14500).
Được rồi, bây giờ như ai đó đã bình chọn cho bài đăng này: Giải pháp này có thực sự đúng không? Tôi nhiều hơn đăng này ở đây để làm cho mọi người chỉ trích nó. Chà, nếu nó đúng, phiên bản chơi gôn của tôi sẽ là:
rand7=lambda:eval("+rand5()"*7)%7+1
mà đi ra đến 37 ký tự.
Java, 65 ký tự:
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
nhưng hoàn toàn chính xác dựa trên lý luận ở đây .
sub rand7{1while($_=5*&rand5-rand5)>6;$_+1}
Điều này đưa ra một cảnh báo về Ambiguous use of -rand5 resolved as -&rand5()
, nhưng hoạt động chính xác. Chuẩn bị một cuộc gọi &
thứ hai cũng rand5
sửa nó với chi phí của một đột quỵ. (Ngược lại, cái khác &
cũng có thể được gỡ bỏ nếu rand5
đã được xác định bằng một ()
nguyên mẫu.)
Thi thiên Phiên bản 46 char sau đây nhanh hơn khoảng ba lần:
sub rand7{1while($_=5*&rand5-rand5)>20;$_%7+1}
int rand7(){int s;while((s=rand5()*5+rand5())<10);return(s%7+1);}
Lâu hơn so với thói quen trước đây, nhưng tôi nghĩ rằng điều này trả về số lượng phân phối đồng đều trong thời gian ít hơn.
PostScript (46)
Điều này sử dụng mã hóa mã thông báo nhị phân, do đó, đây là một 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
Để dùng thử, bạn cũng có thể tải xuống .
Đây là mã không được nhận xét và nhận xét, cùng với mã kiểm tra.
% 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;
Xác định rand7:
rand7=function(n)sample(7,n,T)
Vì R được viết với phân tích thống kê trong đầu, nên nhiệm vụ này không đáng kể và tôi sử dụng hàm tích sample
hợp với bộ thay thế thành TRUE.
Đầu ra mẫu:
> 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
Còn cái này thì sao?
int Rand7()
{
return Rand5()+ Rand5()/2;
}
/
toán tử của nó có làm toán nguyên không? Điều gì xảy ra với kết quả của bạn nếu nó thực hiện phép toán thập phân, dấu phẩy động hoặc số nguyên?
[2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25]
. Không chính xác thống nhất.
int m=0;int rand7(){return(m=m*5&-1>>>1|rand5())%7+1;}
Kiểm tra phân phối:
[1000915, 999689, 999169, 998227, 1001653, 1000419, 999928]
Thuật toán:
> Các con số không bị loại bỏ lẫn nhau nữa, nhưng cá nhân hoàn toàn ngẫu nhiên.
Mã C / C ++ mã lõi chỉ có một dòng!
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 () là hạt giống của rand7, phải gọi hàm này trước rand7, giống như gọi srand trước rand trong C.
Đây là một thứ rất tốt, vì nó chỉ gọi rand () một lần duy nhất và không có điều lặp, không có thêm ký ức.
Hãy để tôi giải thích nó: xem xét một mảng số nguyên với kích thước 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
Vì vậy, chúng tôi đã có BẢNG, mỗi một trong số 1-7 xuất hiện 5 lần trong đó và có tất cả 35 số, vì vậy xác suất của mỗi số là 5/35 = 1/7. Và lần sau,
8th get one number from 1 2 3 4 5
9th get one number from 2 3 4 5 6
......
Sau khi đủ thời gian, chúng ta có thể nhận được phân phối đồng đều từ 1-7.
Vì vậy, chúng ta có thể phân bổ một mảng để khôi phục năm phần tử của 1-7 bằng vòng lặp trái-shift và nhận một số từ mảng mỗi lần bằng rand5. Thay vào đó, chúng ta có thể tạo ra tất cả bảy mảng trước đó và sử dụng chúng theo vòng tròn. Mã cũng đơn giản, có nhiều mã ngắn có thể làm điều này.
Nhưng, chúng ta có thể sử dụng các thuộc tính của% hoạt động, do đó, các hàng 1-7 của bảng tương đương với (rand5 + i)% 7, nghĩa là: a = rand ()% 5 + 1 là rand5 trong ngôn ngữ C, b = gi ++ % 7 tạo ra tất cả các hoán vị trong bảng trên và 0 - 6 thay thế 1 - 7 c = (a + b)% 7 + 1, tạo 1 - 7 đồng đều. Cuối cùng, chúng tôi đã nhận được mã này:
(((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1
Nhưng, chúng tôi không thể nhận được 6 và 7 ở lần gọi đầu tiên, vì vậy chúng tôi cần một hạt giống, một số giống như srand cho rand trong C / C ++, để làm xáo trộn hoán vị cho cuộc gọi chính thức đầu tiên.
Đây là mã đầy đủ để thử nghiệm:
#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
hoặc 7
bằng cách gọi nó một lần ?
int main(){if(rand7()==6) printf("Hello, world!");}
, xấp xỉ bằng vòng lặp sẽ in 'Xin chào, thế giới!' 1 trong 7 lần, nhưng mã của bạn thì không.