First I thought it was simple but the I got stuck, maybe I'm just tired. No matter how I twsit and turn it I seem to get only an even distribution over 5 numbers.
First I thought it was simple but the I got stuck, maybe I'm just tired. No matter how I twsit and turn it I seem to get only an even distribution over 5 numbers.
I didn't want to go through all 5^7 possibilities for the 7-die case, but I figured it's likely enough that he's right that I'd keep my mouth shut.
r = random.Random()
def one_to_five():
return r.randint(1, 5)
def mod_seven():
return (sum(one_to_five() for x in xrange(7)) % 7) + 1
def test_dist(lst):
return [(x, lst.count(x)) for x in [1,2,3,4,5,6,7]]http://spreadsheets.google.com/ccc?key=pq4tB7LQWN03gF7ImGhIP...
edit: Oops bad addition on my part, could be uniform, but you'd have to work out the actual number exactly.
1 -> 11177
2 -> 11172
3 -> 11158
4 -> 11144
5 -> 11144
6 -> 11158
7 -> 11172
...not quite
But, if you want to uniformly map a random number from set X to set Y where (IIRC) lcm(|X|, |Y|) != |X|, it seems you need an infinite worst-case running time.
Here's an informal proof that you can't have a finite upper bound to the number of iterations. After n iterations, you have |X|^n possible outcomes. But, since lcm(|X|, |Y|) != |X|, |X|^n cannot be divided evenly by |Y| (since its factors are the same). So some outcomes in Y must be more likely than others.
(This is not nearly complete, but hopefully it's enough to show how it might be right.)
Of course, in practice it is highly unlikely that you will get past more than a couple iterations before determining an outcome.
Can you go into more detail about this part?
Here is an explanation with the new condition:
Let p be any prime factor of |Y| that |X| does not have. It follows from Euclid's First Theorem[1] that p cannot divide |X|^n for any n [2]. Since every integer (> 1) has a unique prime factorization, it follows that |X|^n can't divide |Y|, because the prime p divides |Y| but not |X|^n.
[1] http://mathworld.wolfram.com/EuclidsTheorems.html [2] We are given that p does not divide |X|^1. Suppose that p also does not divide |X|^(n-1) for some n > 1. |X|^n = |X|^(n-1) * |X|^1, so by Euclid's First Theorem, if p divides |X|^n it must divide either |X|^(n-1) or |X|^1. We know it divides neither, so p does not divide |X|^n. By induction, this is true for all n > 0.
Now use that process to get 3 binary digits. You get a random number from 0 to 7. If the random number is 0, start again... eventually you'll get a number from 1 to 7, and all numbers have the same chances.
12345 67123 45671 23456 7RRRR
R means "reroll".
Constant time execution in average case. Mathematically provable that it is as unbiased as your rand5() function. Technically not guaranteed to terminate but if you dock me points for that you're technically not guaranteed to survive to the end of the interview, are you.
I'll give you a hint, though - the solution is not elegant at all. Which is part of the point.
(Now you have two bits of randomness evenly distributed among the set {00, 01, 10, 11})
2) Get another number 1 to 5, toss it if it's 5, take the LSB. Call it b.
(Now you have another bit of randomness, evenly distributed among {0,1})
3) if b == 1 and a == 11, start over. else return (4b)+a+1
Python implementation (with the -1 then +1 factored out):
def one_to_seven(debug=False):
a = one_to_five()
while a == 5: a = one_to_five()
b = one_to_five()
while b == 5: b = one_to_five()
b = (b % 2) * 4
if a+b == 8: return one_to_seven()
return a+b(Note: not guaranteed to terminate.)
;; * SPOILER? *
(defun rand7 ()
(loop (let ((result (+ (1- (rand5))
(1- (rand5)))))
(if (< result 7)
(return (1+ result))))))
;; * SPOILER *edit: If it doesn't work I'd like to know why...
If the number is greater than 6 throw it away and repeat, otherwise you have your random number.
http://ariya.blogspot.com/2007/11/random-number-15-to-17.htm...
He gives a few different ways to solve it, most with uniform distribution.
int rand7()
{
return (int)(7.0f * rand5() / 5.0f);
}First convert rand5() to rand2(). The LSB from rand5() has a uniform distribution for the integers 0--3:
int rand2()
{
int n = rand5();
return n!=4 ? n & 1 : rand2();
}
Now we simply build a three bit number: int rand7()
{
int n = rand2();
n |= rand2() << 1;
n |= rand2() << 2;
return n;
}
This gives the proper distribution as well, but it's
not branch free, so really nothing new here.gonna have to think about that some more
if(t > 3)
return t;
else
return 2 + rand15();
}I dunno? will that work?