Given a number, produce another random number that is the same every time and distinct from all other results

后端 未结 3 588
南方客
南方客 2020-11-30 15:24

Basically, I would like help designing an algorithm that takes a given number, and returns a random number that is unrelated to the first number. The stipulations being that

相关标签:
3条回答
  • 2020-11-30 15:57

    Here's an example in C#:

        private void DoIt()
        {
            const long m = 101;
            const long x = 387420489; // must be coprime to m
    
            var multInv = MultiplicativeInverse(x, m);
    
            var nums = new HashSet<long>();
            for (long i = 0; i < 100; ++i)
            {
                var encoded = i*x%m;
                var decoded = encoded*multInv%m;
                Console.WriteLine("{0} => {1} => {2}", i, encoded, decoded);
                if (!nums.Add(encoded))
                {
                    Console.WriteLine("Duplicate");
                }
            }
        }
    
        private long MultiplicativeInverse(long x, long modulus)
        {
            return ExtendedEuclideanDivision(x, modulus).Item1%modulus;
        }
    
        private static Tuple<long, long> ExtendedEuclideanDivision(long a, long b)
        {
            if (a < 0)
            {
                var result = ExtendedEuclideanDivision(-a, b);
                return Tuple.Create(-result.Item1, result.Item2);
            }
            if (b < 0)
            {
                var result = ExtendedEuclideanDivision(a, -b);
                return Tuple.Create(result.Item1, -result.Item2);
            }
            if (b == 0)
            {
                return Tuple.Create(1L, 0L);
            }
            var q = a/b;
            var r = a%b;
            var rslt = ExtendedEuclideanDivision(b, r);
            var s = rslt.Item1;
            var t = rslt.Item2;
            return Tuple.Create(t, s - q*t);
        }
    

    That generates numbers in the range 0-100, from input in the range 0-100. Each input results in a unique output.

    It also shows how to reverse the process, using the multiplicative inverse.

    You can extend the range by increasing the value of m. x must be coprime with m.

    Code cribbed from Eric Lippert's article, A practical use of multiplicative inverses, and a few of the previous articles in that series.

    0 讨论(0)
  • 2020-11-30 16:11

    This sounds like a non-repeating random number generator. There are several possible approaches to this.

    As described in this article, we can generate them by selecting a prime number p and satisfies p % 4 = 3 that is large enough (greater than the maximum value in the output range) and generate them this way:

    int randomNumberUnique(int range_len , int p , int x)
        if(x * 2 < p)
           return (x * x) % p
        else
           return p - (x * x) % p
    

    This algorithm will cover all values in [0 , p) for an input in range [0 , p).

    0 讨论(0)
  • 2020-11-30 16:15

    You can not have completely unrelated (particularly if you want the reverse as well).

    There is a concept of modulo inverse of a number, but this would work only if the range number is a prime, eg. 100 will not work, you would need 101 (a prime). This can provide you a pseudo random number if you want.

    Here is the concept of modulo inverse:

    If there are two numbers a and b, such that

    (a * b) % p = 1
    

    where p is any number, then

    a and b are modular inverses of each other.
    

    For this to be true, if we have to find the modular inverse of a wrt a number p, then a and p must be co-prime, ie. gcd(a,p) = 1

    So, for all numbers in a range to have modular inverses, the range bound must be a prime number.

    A few outputs for range bound 101 will be:

    1 == 1
    2 == 51
    3 == 34
    4 == 76
    etc.
    

    EDIT:

    Hey...actually you know, you can use the combined approach of modulo inverse and the method as defined by @Paul. Since every pair will be unique and all numbers will be covered, your random number can be:

    random(k) = randomUniqueNumber(ModuloInverse(k), p)      //this is Paul's function
    
    0 讨论(0)
提交回复
热议问题