Computer Chess Club Archives


Search

Terms

Messages

Subject: A fast hash -- assuming you are not planning to do incremental updates

Author: Dann Corbit

Date: 23:40:15 06/14/01


Suppose that you have a chessboard represented as 64 characters, and you want to
make a hash from it.  This works well, if you make a 64 bit hash by hashing the
first 32 characters and then the second 32 characters to make two 32 bit chunks.
 It was quite a bit faster than Zobrist hashing.  On the other hand, it cannot
be used to do incremental updates, so you might be sorry you used it if you
decide to go that route.

/*
--------------------------------------------------------------------
fhash.h, originally by Bob Jenkins, December 1996
hash2() and mix() are externally useful functions.
You can use this free for any purpose.  It has no warranty.

Dann Corbit messed around with this suff.  It has been changed for
hashing fixed sizes using a single technique.
--------------------------------------------------------------------
*/

/*
--------------------------------------------------------------------
mix -- mix 3 32-bit values reversibly.
For every delta with one or two bit set, and the deltas of all three
  high bits or all three low bits, whether the original value of a,b,c
  is almost all zero or is uniformly distributed,
* If mix() is run forward or backward, at least 32 bits in a,b,c
  have at least 1/4 probability of changing.
* If mix() is run forward, every bit of c will change between 1/3 and
  2/3 of the time.  (Well, 22/100 and 78/100 for some 2-bit deltas.)
mix() was built out of 36 single-cycle latency instructions in a
  structure that could supported 2x parallelism, like so:
      a -= b;
      a -= c; x = (c>>13);
      b -= c; a ^= x;
      b -= a; x = (a<<8);
      c -= a; b ^= x;
      c -= b; x = (b>>13);
      ...
  Unfortunately, superscalar Pentiums and Sparcs can't take advantage
  of that parallelism.  They've also turned some of those single-cycle
  latency instructions into multi-cycle latency instructions.  Still,
  this is the fastest good hash I could find.  There were about 2^^68
  to choose from.  I only looked at a billion or so.
--------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
  a -= b; a -= c; a ^= (c>>13); \
  b -= c; b -= a; b ^= (a<<8);  \
  c -= a; c -= b; c ^= (b>>13); \
  a -= b; a -= c; a ^= (c>>12); \
  b -= c; b -= a; b ^= (a<<16); \
  c -= a; c -= b; c ^= (b>>5);  \
  a -= b; a -= c; a ^= (c>>3);  \
  b -= c; b -= a; b ^= (a<<10); \
  c -= a; c -= b; c ^= (b>>15); \
}

/*
--------------------------------------------------------------------
 This works on all machines, is identical to hash() on little-endian
 machines, and it is much faster than hash(), but it requires
 -- that the key be an array of unsigned long's,
 -- that all your machines have the same endianness (to share hashes)
 --------------------------------------------------------------------
*/
unsigned long   hash2(unsigned long register *k)
{
    unsigned long register
	            a,
                    b,
                    c;

    /* Set up the internal state */
    a = b = 0x9e3779b9;         /* the golden ratio; an arbitrary value */

    a += k[0];
    b += k[1];
    c = k[2];
    mix(a, b, c);
    a += k[3];
    b += k[4];
    c += k[5];
    mix(a, b, c);
    c += 8;
    b += k[6];
    a += k[7];
    mix(a, b, c);
    return c;
}




This page took 0 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.