aboutsummaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
authorswarmer <swarmer@yandex-team.com>2024-03-21 23:48:00 +0300
committerswarmer <swarmer@yandex-team.com>2024-03-22 00:01:35 +0300
commit44ea9939d4ab7a714648ed97a9ed972629e374a7 (patch)
tree10e5cbdf93e0c4536724d1d1d2a137da2190ee1d /util
parent120d7867596b83d6d954905dabd53fa97bfcdabf (diff)
downloadydb-44ea9939d4ab7a714648ed97a9ed972629e374a7.tar.gz
[util] Handle the negative zero value in the NumericHash
Two equal numbers must produce the same hash value. 35bb6ef6de3ccbb3b5cacd09950a21063814b499
Diffstat (limited to 'util')
-rw-r--r--util/digest/numeric.h7
-rw-r--r--util/generic/hash_ut.cpp23
2 files changed, 30 insertions, 0 deletions
diff --git a/util/digest/numeric.h b/util/digest/numeric.h
index 1e9c74ebbb..791bce55a9 100644
--- a/util/digest/numeric.h
+++ b/util/digest/numeric.h
@@ -3,6 +3,8 @@
#include <util/generic/typelist.h>
#include <util/system/defaults.h>
+#include <type_traits>
+
/*
* original url (now dead): http://www.cris.com/~Ttwang/tech/inthash.htm
* copy: https://gist.github.com/badboy/6267743
@@ -70,6 +72,11 @@ static constexpr T IntHash(T t) noexcept {
*/
template <class T>
static constexpr size_t NumericHash(T t) noexcept {
+ if constexpr (std::is_floating_point<T>::value) {
+ if (t == T(0)) { // the negative zero is equal to the positive zero, but has different bitwise representation
+ t = T(0); // make sure that the hash will be the same for both kind of zeros
+ }
+ }
using TCvt = TFixedWidthUnsignedInt<T>;
union Y_HIDDEN {
diff --git a/util/generic/hash_ut.cpp b/util/generic/hash_ut.cpp
index f8bf4e8eac..78fc5657ce 100644
--- a/util/generic/hash_ut.cpp
+++ b/util/generic/hash_ut.cpp
@@ -62,6 +62,7 @@ class THashTest: public TTestBase {
UNIT_TEST(TestHSetInsertInitializerList);
UNIT_TEST(TestTupleHash);
UNIT_TEST(TestStringHash);
+ UNIT_TEST(TestFloatingPointHash);
UNIT_TEST_SUITE_END();
using hmset = THashMultiSet<char, hash<char>, TEqualTo<char>>;
@@ -115,6 +116,7 @@ protected:
void TestHSetInsertInitializerList();
void TestTupleHash();
void TestStringHash();
+ void TestFloatingPointHash();
};
UNIT_TEST_SUITE_REGISTRATION(THashTest);
@@ -1334,3 +1336,24 @@ void THashTest::TestStringHash() {
UNIT_ASSERT_VALUES_EQUAL(ComputeHash(TStringBuf("hehe")), expected); // TStringBuf
UNIT_ASSERT_VALUES_EQUAL(ComputeHash<const char*>("hehe"), expected); // const char*
}
+
+template <class TFloat>
+static void TestFloatingPointHashImpl() {
+ const TFloat f = 0;
+ Y_ASSERT(f == -f);
+ THashSet<TFloat> set;
+ set.insert(f);
+ UNIT_ASSERT_C(set.contains(-f), TypeName<TFloat>());
+ UNIT_ASSERT_VALUES_EQUAL_C(ComputeHash(f), ComputeHash(-f), TypeName<TFloat>());
+ for (int i = 0; i < 5; ++i) {
+ set.insert(-TFloat(i));
+ set.insert(+TFloat(i));
+ }
+ UNIT_ASSERT_VALUES_EQUAL_C(set.size(), 9, TypeName<TFloat>());
+}
+
+void THashTest::TestFloatingPointHash() {
+ TestFloatingPointHashImpl<float>();
+ TestFloatingPointHashImpl<double>();
+ // TestFloatingPointHashImpl<long double>();
+}