std::unordered_map and the % operator

David Kastrup dak@gnu.org
Thu Mar 13 08:25:00 GMT 2014


Ryan Lewis <me@ryanlewis.net> writes:

> Hi,
>
> Firstly, thanks to all the developers out there for providing a
> wonderful library.
>
> I am curious about the present implementation of the hash table in
> std::unordered_map.
>
> Clearly we need to ensure that the key is in the range [0,
> bucket_count) however, it seems to be that
> a simple modulus is a huge trouble. In particular, profiling my code,
> I can see that the processor stalls for quite some time on the
> modulus. Of 20 second algorithm, five seconds is spent in calls to
> find(). While at this juncture I am not particularly sure, my profile
> report suggests that the vast majority of this time is spent waiting
> on the modulus. On some machines a divide my take up to 24 cycles,
> versus only 1 or 2 for a multiplication.
>
> I am wondering if you maintainers would accept a specialization of
> this type which supports replacing the modulus with a multiplication
> by a so called magic number (e.g. the multiplicative inverse of the
> bucket_size in Z_n for appropriate n).

Huh?  Why would you pick the multiplicative inverse of the bucket_size
in some Z_n?  For one thing, almost all Z_n require division for
multiplication anyway.  Exceptions are n = 2^k, n = 2^k±1 and, with some
complications, n = 2^k±d for d represented by considerably fewer than k
bits.  However, for anything but size n=2^k, you'd want access to mixed
precision multiplication.  So that's basically feasible mostly in
assembly language.

A multiplicative inverse of the bucket size when n=2^k exists only for
odd bucket sizes.

The main problem is that the multiplicative inverse of the bucket size
does not at all help you figuring out the _modulus_ of a number
regarding the bucket size.  It allows you to do a fast division by the
bucket size when you _know_ in advance that the number you are starting
with is _divisable_ by the bucket size in Z.  But when you know that,
the modulus is trivially 0.

> In particular, this number can be recomputed whenever the bucket_size
> changes and cached. It seems to me that this will be a performance win
> in almost all cases.

I suggest that you try your explanation again.  It may very well be that
you have a feasible idea about what the code should be doing, but the
math you use to explain it does not appear to map usefully to code.

-- 
David Kastrup



More information about the Libstdc++ mailing list