This is rather detrimental for the search speed. Because of the way a tree is traversed, positions are revisited in a time proportional to the effort that was needed to search them, which furthermore increases for later visits, until it isn't revisited at all. So ideally you would want to keep an entry during a time that is proportional to the time needed to produce entries of that depth. Then a slot in the TT is either used to store a deep entry for a long time, saving a lot of work on a hit, or (sequentially) a lot of low-depth entries, each hit on them saving less work, but the total savings amounting to the same. Keeping it longer is counter-productive, because the hit rate falls in time, and to keep it much longer with a low hit rate goes at the expense of time that shallower entries could be stored with high hit rate (and vice versa).
I now use a very simple replacement scheme to achieve that, by using undercut replacement instead of pure always-replace, in combination with depth-preferred (with aging). 'Undercut' replacement can be seen as a weakened version of depth-preferred: instead of only replacing when the new depth is larger than or equal to the stored depth, it also allows replacement by entries that are exactly 1 ply less deep. For d=0 or d=1 entries this makes no difference, as they will always get replaced. But entries of larger depth will get replaced less frequently, as most attempts to conquer their slot will not have enough depth to manage that. E.g. an entry with d=8 is immune to replacement by all nodes with d=0 to 6, and will survive for a long time in the table. Entries that are refused for the undercut slot will be deferred to a true always-replace slot of the hash bucket.
An easy implementation of this is:
Code: Select all
HashEntry *h = hashTable + (index & mask); // mask has LSB cleared, so h points to an even (always-replace) slot now
if(h->lock == key || (++h)->lock == key) { // hash hit (tested always-replace slot first, as that gives most hits)
...
} else { // hash miss; replace ('h' now points to higest (odd) member of pair, which is the undercut slot)
h -= (depth < h->depth - 1); // if new depth not enough to replace that, go back to always-replace slot
h->lock = key; // replace
h->depth = depth;
...
}
Code: Select all
h -= (depth < h->depth - !(nodeCount & 15));
Code: Select all
h -= (depth == depth - 1 && (h->flags += 16) < 16 || depth < h->depth - 1); // supposes 'flags' unsigned