Cantorのペアリング機能は、シンプルで高速かつスペース効率が良いことを考えると、実に優れた機能の 1つですが、Wolframには、Matthew Szudzikによってさらに優れた機能が公開されています。Cantorペアリング関数の制限は、(比較的)2N
入力が2 N
ビット整数の場合、エンコードされた結果の範囲が常にビット整数の制限内にとどまるとは限らないことです。つまり、私の入力がから2 16
ビットの整数である場合、可能な入力の組み合わせが0 to 2^16 -1
存在する2^16 * (2^16 -1)
ため、明らかなピジョンホール原理により、少なくとも2^16 * (2^16 -1)
に等しいサイズの出力、2^32 - 2^16
つまりのマップが必要です。32
ビット数は理想的に実現可能でなければなりません。これは、プログラミングの世界ではほとんど実用的ではないかもしれません。
カンターペアリング機能:
(a + b) * (a + b + 1) / 2 + a; where a, b >= 0
2つの最大16ビット整数(65535、65535)のマッピングは8589803520であり、32ビットには適合しません。
Szudzikの関数を入力します。
a >= b ? a * a + a + b : a + b * b; where a, b >= 0
(65535、65535)のマッピングは4294967295になり、32ビット(0から2 ^ 32 -1)の整数になります。これがこのソリューションが理想的な場所です。それは単にその空間内のすべての単一のポイントを利用するので、より効率的なスペースを得ることができるものはありません。
言語/フレームワークでさまざまなサイズの数の符号付き実装を通常扱うという事実を考慮して、signed 16
ビット整数を範囲として考えてみ-(2^15) to 2^15 -1
ましょう(後で、符号付き範囲にまたがるように出力を拡張する方法を見ていきます)。以来a
、b
それらは正の範囲である必要があり0 to 2^15 - 1
ます。
カンターペアリング機能:
2つの最大16ビット符号付き整数(32767、32767)のマッピングは2147418112になり、符号付き32ビット整数の最大値にわずかに達します。
今Szudzikの機能:
(32767、32767)=> 1073741823、はるかに小さい。
負の整数を考慮に入れましょう。それは私が知っている元の質問を超えていますが、将来の訪問者を助けるために精巧にしています。
カンターペアリング機能:
A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
(A + B) * (A + B + 1) / 2 + A;
(-32768、-32768)=> 8589803520(Int64)。16ビット入力の64ビット出力はとても許されないかもしれません!!
ズジクの機能:
A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
A >= B ? A * A + A + B : A + B * B;
(-32768、-32768)=> 4294967295これは、符号なし範囲の場合は32ビット、符号付き範囲の場合は64ビットですが、さらに優れています。
これで、出力は常にプラスになっていますが、符号付きの世界では、出力の半分を負の軸に転送できれば、さらにスペースを節約できます。あなたはSzudzikのためにこれのようにそれをすることができます:
A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
C = (A >= B ? A * A + A + B : A + B * B) / 2;
a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
(-32768, 32767) => -2147483648
(32767, -32768) => -2147450880
(0, 0) => 0
(32767, 32767) => 2147418112
(-32768, -32768) => 2147483647
何をするか:2
入力にの重みを適用して関数を通過した後、出力を2で割り、を掛けてそれらのいくつかを負の軸にし-1
ます。
結果を参照してください。符号付き16
ビット番号の範囲の入力については、出力32
はクールな符号付きビット整数の制限内にあります。Cantorペアリング機能について同じ方法をどのように実行するかはわかりませんが、それほど効率的ではありませんでした。さらに、Cantorペアリング関数に含まれる計算が増えると、計算も遅くなります。
これはC#の実装です。
public static long PerfectlyHashThem(int a, int b)
{
var A = (ulong)(a >= 0 ? 2 * (long)a : -2 * (long)a - 1);
var B = (ulong)(b >= 0 ? 2 * (long)b : -2 * (long)b - 1);
var C = (long)((A >= B ? A * A + A + B : A + B * B) / 2);
return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
}
public static int PerfectlyHashThem(short a, short b)
{
var A = (uint)(a >= 0 ? 2 * a : -2 * a - 1);
var B = (uint)(b >= 0 ? 2 * b : -2 * b - 1);
var C = (int)((A >= B ? A * A + A + B : A + B * B) / 2);
return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
}
中間計算は2N
符号付き整数の制限を超える可能性があるため、4N
整数型を使用しました(最後の除算による2
結果はに戻ります2N
)。
私が代替ソリューションで提供したリンクは、空間内のすべての単一点を利用する関数のグラフをうまく表しています。座標のペアを1つの数値に可逆的に一意にエンコードできることは驚くべきことです。数字の魔法の世界!!