Если (x1, y1)
и (x2, y2)
- две случайные пары входов, то пусть f1 = f(x1,y1)
и f2 = f(x2,y2)
.
То, что вы хотите сделать, это минимизировать
P( f(x1,y1) = f(x2,y2) )
= P(f1 = f2)
= sum for i in [LONG_MIN ... LONG_MAX]
of P(f1 = i) * P(f2 = i)
= sum for i in [LONG_MIN ... LONG_MAX]
of P(f1 = i)^2
Таким образом, вы хотите минимизировать сумму квадратов вероятностей каждого из выходов вашей функции. Поскольку сумма вероятностей должна быть 1, мы знаем:
sum for i in [LONG_MIN ... LONG_MAX]
of P(f1 = i)
= 1
И мы также знаем, что для всех i, P(f1 = i)
находится между 0 и 1 (включительно). Таким образом, интуитивно, минимизируя P(f1 = f2)
, нужно сделать распределение вероятностей f1
как можно более равномерным. (Это может быть доказано математически, но это не очень важно для вопроса.) В идеале P(f1 = i)
и P(f1 = j)
должны быть одинаковыми для всех long s i
и j
.
Теперь давайте рассмотрим некоторые различные возможности для природы х и у.
Сначала общий случай, когда x и y равномерно распределены по диапазону long . (Другими словами, x в равной степени может быть любым длинным. Как и y.) В этом случае мы можем указать f(x, y) = x+y
, или f(x,y) = x-y
, или f(x,y) = x XOR y
, или даже f(x,y) = x
и ( при условии нормального целочисленного переполнения) мы находим, что у нас также есть равномерно распределенное f, что означает, что все эти функции «оптимальны».
Но пример f(x,y) = x
показывает вам, что на самом деле вы можете не так много здесь заработать.
Однако на практике ваши x и y, вероятно, не будут распределены равномерно. Например, если x и y оба нарисованы случайным образом из диапазона [0, 9999], то использование f(x,y) = x + y * 10000
будет всегда , чтобы получить разные выходные данные для разных входных данных.
Если в каждой паре (x, y) весьма вероятно, что x и y будут рядом друг с другом, например, (1240,1249), (1,3), (-159720, -159721), то f(x,y) = x
на самом деле довольно хорошая функция-кандидат.
Если x и y «вероятно, невелики», то вам следует объединить 16 младших битов x с 16 младшими битами y, то есть f(x,y) = ((x&0xFFFF) << 16) | (y&0xFFFF)
, поскольку младшие биты будут распределены более равномерно, чем старшие биты .
Это работает очень хорошо, если x и y никогда не бывают отрицательными. Но если они есть, знаковый бит (который указывает, является ли число положительным или отрицательным), может быть распределен более равномерно, чем некоторые из 16 младших битов. Таким образом, вы можете использовать его вместо этого. Э.Г.
f(x,y) = ((x&0x7FFF) << 17) | ((y&0x7FFF) << 2) | ((x>>30) & 2) | (y>>31)
Поскольку случай «вероятно, не очень большой» довольно распространен, я думаю, что эта функция на самом деле будет работать довольно хорошо.