2

I am trying to create a function that generates a hash key based upon where in the hash table I want the value to go.

My hash function is (a + b * (key) ) % c = hash value. I've seen a similar question to this on SO, and what I tried is replacing b * (key) with d and just doing:

private int ReverseModulus(int a, int b, int c, int hashValue)
{
   if(hashValue >= c)
      return -1;
   if(a < hashValue)
      return (hashValue - a) / b;
   return (c + hashValue - a) / b;
}

but it seems that most of the time hashValue != Hash(ReverseModulus(a,b,c, hashValue)).

I was wondering if the approach is wrong or if there is just an error in the code.

Community
  • 1
  • 1
Jedi_Maseter_Sam
  • 753
  • 4
  • 24
  • 7
    Hashes are, by design, one way. – Servy Feb 21 '17 at 21:01
  • I think you want to read [Perfect Hash Function](https://en.wikipedia.org/wiki/Perfect_hash_function) – Jim Garrison Feb 21 '17 at 21:03
  • I know there is not a one-to-one relationship between keys and hash values, but I just want to get one out of the infinite number of keys that will produce the desired hash value. For example, you could brute force it by iterating from 0 onward until you get the correct hash value. – Jedi_Maseter_Sam Feb 21 '17 at 21:03
  • @Servy Well, insofar as you call a linear congruential generator a hash.... – Charles Feb 21 '17 at 21:09
  • If you already know what the hash value you want is, then just return that value. No need to do any calculation. – rossum Feb 21 '17 at 21:12
  • 1
    @Servy Not True. There are plenty of reversible hashes. Hashes have to be specifically designed to be one way. – SledgeHammer Feb 21 '17 at 21:13
  • Are `a`, `b`, and `c` constants (compiled into the program)? Or do you want to be able to change them when the program runs? If they are constants, what's are their values? – erickson Feb 22 '17 at 19:30
  • `c` is the first prime number that is at least the size of the hash table. `a` and `b` are both random numbers between 0 and `c - 1` – Jedi_Maseter_Sam Feb 22 '17 at 20:17

1 Answers1

0

You're using the wrong kind of division. You're doing integer division, but you need to be doing modular division. In Java you can use BigInteger:

bh = new BigInteger(hashValue);
ba = new BigInteger(a);
bc = new BigInteger(c);
bn = bh.subtract(ba);
return bn.modInverse(bc).intValue();

and C# presumably has similar library functions.

Charles
  • 11,269
  • 13
  • 67
  • 105
  • 1
    Shouldn't it be `bn.multiply(bb.modInverse(bc))`? Also, you need to use `BigInteger.valueOf()`, not `new BigInteger()`. Finally, the inverse of the multiplier should be a constant and all of this performed as `int` arithmetic for efficiency: `return (h - a) * B_INV;` – erickson Feb 21 '17 at 22:15
  • @erickson I just tested your suggestion and it works. Just curious, what is `B_INV` referring to? – Jedi_Maseter_Sam Feb 21 '17 at 22:21
  • 1
    @Jedi_Maseter_Sam `B_INV` is the multiplicative inverse of `b`, modulo `c`. I am assuming that `c` is 2^32, but if it's not, you'll just need one extra operation instead of relying on `int` arithmetic overflow. You get 1 if you multiply `b` and `B_INV`, modulo `c`. You can compute `B_INV` as `BigInteger bb = BigInteger.valueOf(b), bc = BigInteger.valueOf(c); int B_INV = bb.modInverse(bc).intValue();` Do this when your program starts up, or the pertinent class is initialized, or even figure it out and write it into your program. Then you can save unnecessary `BigInteger` expense. – erickson Feb 21 '17 at 23:03