Для заданного числа создайте другое случайное число, которое каждый раз будет одинаковым и отличным от всех других результатов.

По сути, я хотел бы помочь разработать алгоритм, который принимает заданное число и возвращает случайное число, не связанное с первым числом. Условия заключаются в том, что а) данное выходное число всегда будет одинаковым для аналогичного входного числа, и б) в пределах определенного диапазона (например, 1-100) все выходные числа будут разными. т.е. никакие два разных входных числа меньше 100 не дадут одинаковый выходной номер.

Я знаю, что это легко сделать, создав упорядоченный список чисел, перемешивая их случайным образом, а затем возвращая индекс ввода. Но я хочу знать, можно ли это сделать вообще без кеширования. Может быть, с каким-то алгоритмом хеширования? В основном причина этого в том, что если бы диапазон возможных выходов был намного больше, скажем 10000000000, тогда было бы нелепо генерировать весь диапазон чисел, а затем перемешивать их случайным образом, если бы вы собирались получить только несколько результатов из Это.

Неважно, на каком языке это написано, я просто хочу знать, возможно ли это. Я долго думал об этой проблеме и не могу придумать другого решения, кроме того, которое я уже придумал.

Изменить: у меня просто была другая идея; Было бы интересно иметь другой алгоритм, который возвращал бы обратный первому. Было бы интересно исследовать, возможно ли это.


person Maurdekye    schedule 22.12.2015    source источник
comment
вы можете сделать это с помощью простых вычислений и кеширования некоторой части информации (в основном, какое случайное число было возвращено для ввода X, чтобы вы могли получить согласованные возвращаемые значения, которые вы запрашивали).   -  person MaxOvrdrv    schedule 22.12.2015
comment
Я бы предпочел, чтобы кеширование вообще не выполнялось. Кроме того, этот алгоритм может стать неэффективным через некоторое время, когда случайный результат придется генерировать несколько раз, чтобы убедиться, что он не соответствует другим ответам. Кроме того, это не сохраняет сходство между средами выполнения. Чисто математический результат дал бы не только одинаковые выходные данные для ввода между разными средами выполнения, но и на разных компьютерах полностью. Вот какое решение я ищу.   -  person Maurdekye    schedule 22.12.2015
comment
Вы ищете мультипликативную инверсию.   -  person Jim Mischel    schedule 22.12.2015
comment
Не хотели бы вы помещать ответы, даже простые, в качестве ответов вместо комментариев?   -  person Roberto    schedule 22.12.2015
comment
Нет, я не Джим. Числа входа и выхода не должны иметь отношения друг к другу, кроме алгоритма. Это должно быть похоже на алгоритм случайной генерации.   -  person Maurdekye    schedule 22.12.2015
comment
@Maurdekye: Если вы прокрутите вниз до раздела «Приложения» этой статьи, вы увидите следующее: Расширение обратного 1 / q в любой базе также может действовать как источник псевдослучайных чисел. См. Практическое использование мультипликативных инверсий для примера.   -  person Jim Mischel    schedule 22.12.2015
comment
хорошо, так что в основном вы ищете своего рода механизм семени ... например: если семя - X, то результат вычисления всегда будет Y ... однако я не знаю ни одного алгоритма / сеялки, который также вернуть тот же результат для похожих семян ... это часть, которая немного противоречит вашим требованиям ...   -  person MaxOvrdrv    schedule 22.12.2015
comment
Ха, я думаю, это может иметь отношение к моей проблеме, Джим. Я разберусь с этим. Хотя я бы предпочел, чтобы вы разместили это как ответ.   -  person Maurdekye    schedule 22.12.2015
comment
Вопрос странный. Вы запрашиваете такую ​​связь между числами, чтобы числа были не связаны, за исключением отношения. Я не могу придумать, как провести различие между отношениями, в которых связанные числа не связаны, за исключением отношения, и отношениями, в которых связанные числа связаны другими способами, кроме отношения. Как начать отвечать на этот вопрос?   -  person Eric Lippert    schedule 23.12.2015
comment
Вы можете попробовать Skip32 Encryption (предупреждение: не используйте для реального шифрования), но мультипликативный инверсный вариант подходит гораздо лучше.   -  person Brian    schedule 23.12.2015


Ответы (3)


Это похоже на неповторяющийся генератор случайных чисел. Есть несколько возможных подходов к этому.

Как описано в этой статье, мы можем сгенерировать их, выбрав простое число p и удовлетворив p % 4 = 3, которое достаточно велико (больше максимального значения в выходном диапазоне), и сгенерировать их следующим образом:

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

Этот алгоритм будет охватывать все значения в [0 , p) для входа в диапазоне [0 , p).

person Paul    schedule 22.12.2015
comment
Я пробовал использовать ваш метод, но результаты не были уникальными. Используя предел диапазона 101, я сгенерировал все числа от 0 до 100 и получил только 51 уникальный результат. - person Maurdekye; 22.12.2015
comment
@Maurdekye sry, я забыл свойство p. Я отредактировал пост. Сам код работает нормально, если p удовлетворяет p % 4 = 3. Например, он работает с p = 103. - person Paul; 22.12.2015
comment
Значит, p должно быть простым и на единицу меньше делителя 4? это приличное количество условий для ограничения диапазона. Возможно ли произвольное ограничение без этих требований? - person Maurdekye; 22.12.2015
comment
@Maurdekye конечно. Только p должно соответствовать этим ограничениям. Сам диапазон может иметь произвольный предел, если максимальное значение меньше p. Только некоторые значения, которые находятся в диапазоне, не будут охвачены, если p больше, чем предел диапазона. - person Paul; 23.12.2015

Вот пример на 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);
    }

Это генерирует числа в диапазоне 0-100 из ввода в диапазоне 0-100. Каждый ввод приводит к уникальному результату.

Он также показывает, как обратить процесс, используя мультипликативное обратное.

Вы можете расширить диапазон, увеличив значение m. x должен быть взаимно прост с m.

Код взят из статьи Эрика Липперта Практическое использование мультипликативного обратное и несколько предыдущих статей из этой серии.

person Jim Mischel    schedule 22.12.2015

Вы не можете быть совершенно не связанными (особенно если вы хотите и обратное).

Существует концепция modulo inverse числа, но это будет работать, только если range число является простым, например. 100 не подойдет, понадобится 101 (простое). Это может предоставить вам псевдослучайное число, если хотите.

Вот концепция обратного по модулю:

Если есть два числа a and b, такие что

(a * b) % p = 1

где p - любое число, тогда

a and b are modular inverses of each other.

Чтобы это было правдой, если нам нужно найти модульную инверсию a относительно числа p, тогда a and p должен быть взаимно простым, т.е. gcd(a,p) = 1

Итак, чтобы все числа в диапазоне имели модульные обратные значения, граница диапазона должна быть простым числом.

Несколько выходных данных для диапазона 101 будут:

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

РЕДАКТИРОВАТЬ:

Эй ... на самом деле вы знаете, вы можете использовать комбинированный подход обратного по модулю и метода, определенного @Paul. Поскольку каждая пара будет уникальной и все числа будут покрыты, ваше случайное число может быть:

random(k) = randomUniqueNumber(ModuloInverse(k), p)      //this is Paul's function
person vish4071    schedule 22.12.2015
comment
Очень интересно. Хотя у вас, кажется, есть относительно полный ответ, я также был связан в этой статье, в которой, кажется, говорится, что возможно иметь диапазон произвольного размера, не являющийся простым числом. Я продолжу изучать проблему, если вы не скажете что-нибудь по этому поводу. - person Maurdekye; 22.12.2015
comment
@Maurdekye, пожалуйста, посмотрите РЕДАКТИРОВАТЬ (в ответ). Это может помочь. - person vish4071; 23.12.2015