At the moment, boost::hash_value for complex<T> is specified as When T is a built in type and val.imag() == 0, the result is equal to hash_value(val.real()). Otherwise an unspecified value, except that equal arguments shall yield the same result. This is a bit odd; the natural implementation for a two-argument point/tuple type is std::size_t seed = 0; boost::hash_combine( seed, v.real() ); boost::hash_combine( seed, v.imag() ); return seed; Can anyone offer an opinion on whether or why the original behavior is preferable?
Given two values x and y, if x == y, it is convenient for hash(x) == hash(y).
In this situation, given a floating point value r, complex{r) == r, so it makes sense that hash(complex{r}) == hash(r). This might enable heterogeneous hash table lookup.
Howard
On Oct 16, 2021, at 6:44 PM, Peter Dimov via Boost
At the moment, boost::hash_value for complex<T> is specified as
When T is a built in type and val.imag() == 0, the result is equal to hash_value(val.real()). Otherwise an unspecified value, except that equal arguments shall yield the same result.
This is a bit odd; the natural implementation for a two-argument point/tuple type is
std::size_t seed = 0;
boost::hash_combine( seed, v.real() ); boost::hash_combine( seed, v.imag() );
return seed;
Can anyone offer an opinion on whether or why the original behavior is preferable?
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Howard Hinnant wrote:
Given two values x and y, if x == y, it is convenient for hash(x) == hash(y).
In this situation, given a floating point value r, complex{r) == r, so it makes sense that hash(complex{r}) == hash(r). This might enable heterogeneous hash table lookup.
But that already doesn't hold in general for int/long, float/double, int/double, and so on.
On Oct 16, 2021, at 7:58 PM, Peter Dimov
Howard Hinnant wrote:
Given two values x and y, if x == y, it is convenient for hash(x) == hash(y).
In this situation, given a floating point value r, complex{r) == r, so it makes sense that hash(complex{r}) == hash(r). This might enable heterogeneous hash table lookup.
But that already doesn't hold in general for int/long, float/double, int/double, and so on.
True, but it also doesn’t not hold. :-) So it’s a design question: should equal values hash equal, even if they are different types? The rationale for yes is to enable heterogenous lookup. The rationale for no is that it is not done that way for nearly all types (excepting maybe complex/real, and I’m not sure about string/string_view). There may also be performance penalties for supporting heterogeneous lookup this way because such exceptions might disable a “contiguously hashable” attribute (which isn’t really relevant for hash_combine). So either way isn’t a slam dunk. But I’ve offered a potential advantage on "the original behavior.” Howard
On 10/17/21 1:44 AM, Peter Dimov via Boost wrote:
At the moment, boost::hash_value for complex<T> is specified as
When T is a built in type and val.imag() == 0, the result is equal to hash_value(val.real()). Otherwise an unspecified value, except that equal arguments shall yield the same result.
This is a bit odd; the natural implementation for a two-argument point/tuple type is
std::size_t seed = 0;
boost::hash_combine( seed, v.real() ); boost::hash_combine( seed, v.imag() );
return seed;
Can anyone offer an opinion on whether or why the original behavior is preferable?
Not that I have a particular opinion on one way or another, but having the hash changing the value between releases could be a breaking change, if someone is using it e.g. in a memory mapped file. If the hash values change as a result of your work, please be sure to mention it in the release notes.
Andrey Semashev wrote:
Not that I have a particular opinion on one way or another, but having the hash changing the value between releases could be a breaking change, if someone is using it e.g. in a memory mapped file.
Sure. As far as I can see, however, boost::hash has never promised hash stability, and the hash values have already changed a number of times.
Andrey Semashev wrote:
Not that I have a particular opinion on one way or another, but having the hash changing the value between releases could be a breaking change, if someone is using it e.g. in a memory mapped file.
Sure. As far as I can see, however, boost::hash has never promised hash stability, and the hash values have already changed a number of times.
On second thought, you are right. While it's true that boost::hash does not promise hash stability in principle, and that hash values have indeed changed a number of times, the library has been relatively stable so it's possible that people do depend on hash stability, and this should be kept in mind. Thanks. I'm about to add a test with reference values that will tell us if some of them change, whether inadvertently or by design. The commit history of this test will also be usable as a log of which release changed which hash values. https://github.com/boostorg/container_hash/blob/feature/reference/test/hash_...
participants (3)
-
Andrey Semashev
-
Howard Hinnant
-
Peter Dimov