From the theoretical information representation, you have the values 2^64 to display in the values 2^63-1 .
Thus, the mapping is trivial with the module operator, since it always has a non-negative result:
y = 1 + x % 0x7fffffffffffffff;
It can be quite expensive, so what else is possible?
Simple math 2^64 = 2 * (2^63 - 1) + 2 says that we will have two source values for one target value, except for two special cases where three will go to one. Think of it as two special 64-bit values, name them x1 and x2 so that everyone shares the target with two other source values. In the mod expression above, this happens by "wrapping". The target values y=2^31-2 and y=2^31-3 have three mappings. Everyone else has two. Since in any case, we should use something more complex than mod , let's look for a way to match special values wherever we like, at a low cost
For illustration, let's work with matching a 4-bit signed int x in [-8..7] to y in [1..7], and not with 64-bit space.
An easy course is to have the values of x in [1..7] for yourself, then the task is reduced to mapping x in [-8..0] to y in [1 .. 7]. Note that there are 9 initial values and only 7 goals, as discussed above.
There are many strategies. At this point, you are likely to see gazillion. I will describe only one that is especially simple.
Let y = 1 - x for all values, except in special cases x1 == -8 and x2 == -7 . So the whole hash function becomes
y = x <= -7 ? S(x) : x <= 0 ? 1 - x : x;
Here S(x) is a simple function that says where x1 and x2 displayed. Choose S based on what you know about the data. For example, if you think that high target values are unlikely, compare them with 6 and 7 with S(x) = -1 - x .
Final display:
-8: 7 -7: 6 -6: 7 -5: 6 -4: 5 -3: 4 -2: 3 -1: 2 0: 1 1: 1 2: 2 3: 3 4: 4 5: 5 6: 6 7: 7
Taking this logic up to 64-bit space, you will have
y = (x <= Long.MIN_VALUE + 1) ? -1 - x : x <= 0 ? 1 - x : x;
Many other settings are possible in this structure.