You are provided with a function Rand5(). This function returns perfectly random (equal distribution) integers between 1 and 5.
Provide the function Rand7(), which uses Rand5() to produce perfectly random integers between 1 and 7.
You are provided with a function Rand5(). This function returns perfectly random (equal distribution) integers between 1 and 5.
Provide the function Rand7(), which uses Rand5() to produce perfectly random integers between 1 and 7.
Java - 61 chars
int rand7(){int s=0,c=7;while(c-->0)s+=rand5();return s%7+1;}
Test driver for validation:
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;}
}
Results
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
. I computed them in Maple using simple matrix algebra, but you can do it with pencil and paper in a few minutes if you want. Anyway, it turns out Omar already posted the same figures (sans normalizing factor) in a comment to another answer a couple of days earlier. (Also ps., you can only @notify one user per comment, although the post's author is notified always in any case.)
\$\endgroup\$
Commented
Dec 8, 2011 at 0:27
sub rand7{($x=5*&rand5+&rand5-3)<24?int($x/3):&rand7}
Plus I get to use the ternary operator AND recursion. Best... day... ever!
OK, 47 chars if you use mod instead of div:
sub rand7{($x=5*&rand5+&rand5)<27?$x%7+1:&rand7}
&
signs to get it down to 46 chars (including the space, which puts your current version at 48).
\$\endgroup\$
Commented
Dec 1, 2011 at 23:25
In Python:
def Rand7():
while True:
x = (Rand5() - 1) * 5 + (Rand5() - 1)
if x < 21: return x/3 + 1
return x//3 + 1
\$\endgroup\$
Ruby - 54 chars (based on Dan McGrath solution, using loop)
def rand7;x=8;while x>7 do x=rand5+5*rand5-5 end;x;end
Ruby - 45 chars (same solution, using recursion)
def rand7;x=rand5+5*rand5-5;x>7 ?rand7: x;end
(x=rand5+5*rand5-5)>7?
.
\$\endgroup\$
Commented
May 9, 2011 at 13:17
Rand7=f=_=>(x=Rand5()+Rand5()*5-5)>7?f():x
Bonus ES5 thing:
Rand7=eval.bind(0,'for(;x=Rand5()+Rand5()*5-5,x>7;);x')
In Common Lisp 70 characters:
(defun rand7()(let((n(-(+(rand5)(* 5(rand5)))5)))(if(> n 7)(rand7)n)))
The parenthesis take up more space than I would like.
(defun rand7()(setq n(-(+(rand5)(* 5(rand5)))5))(if(> n 7)(rand7)n))
\$\endgroup\$
(defun rand7()(if(>(setq n(-(+(rand5)(* 5(rand5)))5))7)(rand7)n))
\$\endgroup\$
Translation to PHP, from the answer posted ny Dan McGrath.
function Rand7(){$x=8;while($x>7)$x=rand5()+5*rand5()-5;return $x;}
67 characters.
In c/c++ using rejection sampling
int rand7(){int x=8;while(x>7)x=rand5()+5*rand5()-5;return x;}
62 characters.
while(x>7)
, so that would only be satisfied by numbers in the valid range.
\$\endgroup\$
Commented
Apr 25, 2011 at 17:14
In R (a language built for statistical computation), a deliberately cheaterish solution:
# 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()]
Thanks to lazy evaluation of arguments, I eliminated the semicolon and braces.
Output over 10^6 replicates:
> 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]}
\$\endgroup\$
Commented
Dec 2, 2011 at 18:02
Rand7=function(){sample(7)[Rand5()]}
\$\endgroup\$
Commented
Dec 2, 2011 at 18:22
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);
}
Numbers distribution (1000000 integers):
142935 142751 142652 143299 142969 142691 142703
Average number of calls to Rand5() per every generated integer is about 2.2 (2 to 10+).
1 2 3 4 5 6 7 8 9 10
0 840180 112222 44433 2212 886 0 60 6 1
def rand7:Int={val r=5*(rand5-1)+rand5
if(r<8)r else rand7}
with 2 inputs from rand5:
\ 1 2 3 4 5
1 1 2 3 4 5
2 6 7 8 ..
3 11 ..
4 ..
5
I multiply the first-1 by 5, and add the second. Most results are ignored, and lead to a new calculation. The result should be an equal distribution of values from 1-25, from which I only pick the first 7 ones. I could accept the first 21 with building a modulo, but this would lead to longer code.
historic code which failed, but not very obviously. Thanks to Ilmari Karonen for pointing it out:
def rand7=(1 to 7).map(_=>rand5).sum%7+1
Thanks to Yoshiteru Takeshita, for this scala-2.8.0-approach which made 'sum' so easy. My solution before:
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
\$\endgroup\$
Commented
Sep 28, 2011 at 8:01
In Java (or C/C++ I suppose)
using generation formula by Alexandru, in 65 characters:
int rand7(){int x=rand5()*5+rand5()-6;return x>20?rand7():x/3+1;}
using generation formula by Dan McGrath, in 60 characters
int rand7(){int x=rand5()+5*rand5()-5;return x>7?rand7():x;}
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;}
Translation to Javascript, from the answer posted by Dan McGrath.
function Rand7(){x=8;while(x>7)x=rand5()+5*rand5()-5;return x}
62 chars
function Rand7(){for(x=8;x>7;x=rand5()+5*rand5()-5);return x}
is little shorter :P
\$\endgroup\$
Another solution that may be wrong, in Python:
rand7 = lambda: sum(rand5() for i in range(7)) % 7 + 1
This seems to be too simple, but when I try:
counter = [0] * 7
for i in range(100000):
counter[rand7()] += 1
I get a reasonably even distribution (all between 14000 and 14500).
Okay, now as somebody voted for this post: Is this solution indeed correct? I more posted this here to make people criticize it. Well, if it is correct, my golfed version would be:
rand7=lambda:eval("+rand5()"*7)%7+1
which comes out to 37 chars.
function Rand7(){for(x=0,i=1;i<8;x^=i*((k=Rand5())%2),i*=1+(k<5));return x?x:Rand7()}
I know there's shorter answer, but I wanted to show the test of this puzzle. It turns out that only Clyde Lobo's answer using Dan McGrath's rejection sampling is correct (between JS answers).
Java, 65 chars:
int rand7(){int r;do{r=rand5()+5*rand5()-5;}while(r>7);return r;}
int rand7(){int s;while((s=rand5()*5+rand5())<10);return(s%7+1);}
Longer than previous routine, but I think this one returns uniformly distributed numbers in less time.
(defn rand7[](#(if(<% 8)%(rand7))(+(rand5)(*(rand5)5)-5)))
def rand7():
while True:
n=5*(rand5()-1)+(rand5()-1)
if n<21:return n%7+1
but completely correct based on the reasoning here.
sub rand7{1while($_=5*&rand5-rand5)>6;$_+1}
This gives a warning about Ambiguous use of -rand5 resolved as -&rand5()
, but works correctly. Prepending an &
also to the second rand5
call fixes it at the cost of one stroke. (Conversely, the other &
can also be removed if rand5
has been defined with a ()
prototype.)
Ps. The following 46-char version is about three times faster:
sub rand7{1while($_=5*&rand5-rand5)>20;$_%7+1}
PostScript (46)
This uses binary token encoding, therefore, here is a 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
To try it out, you can also download it.
Here is the ungolfed and commented code, together with testing code.
% 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;
Define rand7:
rand7=function(n)sample(7,n,T)
Because R was written with statistical analysis in mind, this task is trivial, and I use the built-in function sample
with replacement set to TRUE.
Sample output:
> 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={if(b==null)b=rand5();(b=(rand5()+b)%7+1)}
example distribution over 35,000 iterations:
[1:5030, 2:4909, 3:5017, 4:4942, 5:5118, 6:4956, 7:5028]
Is it bad that it's stateful?
How about this?
int Rand7()
{
return Rand5()+ Rand5()/2;
}
/
operator do integer math? What happens to your results if it does decimal, floating-point, or integer math?
\$\endgroup\$
[2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25]
. Not exactly uniform.
\$\endgroup\$
def rand7;(0..7).reduce{|i|i+rand5}%7+1;end
cemper93's solution ported to Ruby is three bytes shorter ;) (34 bytes)
def rand7;eval("+rand5"*7)%7+1;end
int m=0;int rand7(){return(m=m*5&-1>>>1|rand5())%7+1;}
Distribution test:
[1000915, 999689, 999169, 998227, 1001653, 1000419, 999928]
Algorithm:
> The numbers are not mutually uncorrelated anymore, but individually perfectly random.
C/C++ code the core code has one line only!
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();
}
The srand7() is the seed of rand7, must call this function before rand7, just like call srand before rand in C.
This is a very good one, because it call rand() only one time, and no loop thing, no expends extra memories.
Let me explain it: consider a integer array with size of 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
So we got the TABLE, each one of 1-7 appears 5 times in it, and has all 35 numbers, so the probability of each number is 5/35=1/7. And next time,
8th get one number from 1 2 3 4 5
9th get one number from 2 3 4 5 6
......
After enough times, we can get the uniform distribution of 1-7.
So, we can allocate a array to restore the five elements of 1-7 by loop-left-shift, and get one number from array each time by rand5. Instead, we can generate the all seven arrays before, and using them circularly. The code is simple also, has many short codes can do this.
But, we can using the properties of % operation, so the table 1-7 rows is equivalent with (rand5 + i) % 7, that is : a = rand() % 5 + 1 is rand5 in C language, b = gi++ % 7 generates all permutations in table above, and 0 - 6 replace 1 - 7 c = (a + b) % 7 + 1, generates 1 - 7 uniformly. Finally, we got this code:
(((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1
But, we can not get 6 and 7 at first call, so we need a seed, some like srand for rand in C/C++, to disarrange the permutation for first formal call.
Here is the full code to testing:
#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
or 7
by calling it once?
\$\endgroup\$
int main(){if(rand7()==6) printf("Hello, world!");}
, approximation using loop will print 'Hello, world!' 1 in 7 times, but your code doesn't.
\$\endgroup\$