Expand a random range from 1–5 to 1–7

前端 未结 30 3142
一个人的身影
一个人的身影 2020-11-22 07:29

Given a function which produces a random integer in the range 1 to 5, write a function which produces a random integer in the range 1 to 7.

  1. What is a simple so
30条回答
  •  野趣味
    野趣味 (楼主)
    2020-11-22 08:11

    int rand7() {
        int value = rand5()
                  + rand5() * 2
                  + rand5() * 3
                  + rand5() * 4
                  + rand5() * 5
                  + rand5() * 6;
        return value%7;
    }
    

    Unlike the chosen solution, the algorithm will run in constant time. It does however make 2 more calls to rand5 than the average run time of the chosen solution.

    Note that this generator is not perfect (the number 0 has 0.0064% more chance than any other number), but for most practical purposes the guarantee of constant time probably outweighs this inaccuracy.

    Explanation

    This solution is derived from the fact that the number 15,624 is divisible by 7 and thus if we can randomly and uniformly generate numbers from 0 to 15,624 and then take mod 7 we can get a near-uniform rand7 generator. Numbers from 0 to 15,624 can be uniformly generated by rolling rand5 6 times and using them to form the digits of a base 5 number as follows:

    rand5 * 5^5 + rand5 * 5^4 + rand5 * 5^3 + rand5 * 5^2 + rand5 * 5 + rand5
    

    Properties of mod 7 however allow us to simplify the equation a bit:

    5^5 = 3 mod 7
    5^4 = 2 mod 7
    5^3 = 6 mod 7
    5^2 = 4 mod 7
    5^1 = 5 mod 7
    

    So

    rand5 * 5^5 + rand5 * 5^4 + rand5 * 5^3 + rand5 * 5^2 + rand5 * 5 + rand5
    

    becomes

    rand5 * 3 + rand5 * 2 + rand5 * 6 + rand5 * 4 + rand5 * 5 + rand5
    

    Theory

    The number 15,624 was not chosen randomly, but can be discovered using fermat's little theorem, which states that if p is a prime number then

    a^(p-1) = 1 mod p
    

    So this gives us,

    (5^6)-1 = 0 mod 7
    

    (5^6)-1 is equal to

    4 * 5^5 + 4 * 5^4 + 4 * 5^3 + 4 * 5^2 + 4 * 5 + 4
    

    This is a number in base 5 form and thus we can see that this method can be used to go from any random number generator to any other random number generator. Though a small bias towards 0 is always introduced when using the exponent p-1.

    To generalize this approach and to be more accurate we can have a function like this:

    def getRandomconverted(frm, to):
        s = 0
        for i in range(to):
            s += getRandomUniform(frm)*frm**i
        mx = 0
        for i in range(to):
            mx = (to-1)*frm**i 
        mx = int(mx/to)*to # maximum value till which we can take mod
        if s < mx:
            return s%to
        else:
            return getRandomconverted(frm, to)
    

提交回复
热议问题