これはかなりうまくいくようです:
const long multiplier = 6364136223846793005;
const long mulinv_multiplier = -4568919932995229531;
const long offset = 1442695040888963407;
static long Forward(long x)
{
return x * multiplier + offset;
}
static long Reverse(long x)
{
return (x - offset) * mulinv_multiplier;
}
multiplier
定数は、奇数でmulinv_multiplier
モジュラー乗法逆数 ( wiki:モジュラー乗法逆数または Hackers Delight 10-15 Exact Division by Constants を参照) multiplier
(モジュロ 2^64 を参照) である限り、何にでも変更できmultiplier
ます。奇数でなければ、逆数はありません)。
オフセットは何でもかまいませんが、安全のために 2^64 で比較的素数にしてください。
これらの特定の定数は、Knuths 線形合同ジェネレーターから取得されます。
小さなことが 1 つあります。入力の LSB の補数を結果の LSB に入れます。それが問題になる場合は、ゼロ以外の量だけ回転させることができます。
32 ビットの場合、定数はmultiplier = 0x4c957f2d
、offset = 0xf767814f
、mulinv_multiplier = 0x329e28a5
です。
64 ビットの場合はmultiplier = 12790229573962758597
、 のmulinv_multiplier = 16500474117902441741
方がうまくいく場合があります。
または、CRC64 の場合、この用途に可逆な(つまり、入力が CRC と同じサイズである) CRC を使用することもできますが、もちろんいくつかの変更が必要です。