C++ 浮点在哈希表中使用键吗?

C++ 浮点在哈希表中使用键吗?,c++,stl,floating-point,C++,Stl,Floating Point,我知道浮点值不能通过==进行比较。我做了一个像这样的自定义比较函数 auto isEqual = [](const double& a, const double& b) { return fabs(a-b) <= numeric_limits<double>::epsilon(); }; auto-isEqual=[](常数双精度a、常数双精度b){ return fabs(a-b)基本上不可能修改无序映射以使用包含不同舍入错误的浮点值作为键 仅自定义相

我知道浮点值不能通过==进行比较。我做了一个像这样的自定义比较函数

auto isEqual = [](const double& a, const double& b) {
  return fabs(a-b) <= numeric_limits<double>::epsilon();
};
auto-isEqual=[](常数双精度a、常数双精度b){

return fabs(a-b)基本上不可能修改
无序映射
以使用包含不同舍入错误的浮点值作为键

仅自定义相等比较是不够的,因为它仅用于区分通过哈希函数映射到同一个存储桶的值。不同的浮点值通常会哈希到不同的存储桶,即使它们仅存在最小的舍入错误。因此,还必须自定义哈希函数

然而,哈希函数的要求是将浮点值映射为不同的,但是你想把它看作是同一个桶。一般来说,这是不可能的,因为如果你想把两个非常接近的数看成相等的话,那就说它们离浮标很近。ng point格式,则传递性要求哈希函数将所有数字映射到一个bucket。也就是说,由于零和最小的正表示数字必须映射到同一个bucket,最小的正表示数字和第二小的正表示数字必须映射到同一个bucket,然后是零和第二小的正表示数字ber必须映射到同一个存储桶。同样,第三小的数字必须与第二小的数字表示相同的存储桶,因此与零表示相同的存储桶。第四个和第五个数字也是如此。这会创建一个链,该链对所有数字都是连续的:它们必须都映射到同一个存储桶

因此,任何哈希函数都不能用于实现将接近数视为相等的浮点数的非退化映射


在特殊情况下,可以对某些数字集实现合理的哈希。例如,如果已知所有浮点值都表示一个美分数,并且浮点数从不包含达到或超过半美分的累积舍入误差,则每个值都可以舍入到最接近的值t分(或最接近该值的可表示值)在散列之前。请注意,本例中的值域实际上是一个离散集,例如一组定点数,而不是一个连续集,例如浮点算术要近似的实数集。在本例中,唯一需要的修改是量化浮点值(将其四舍五入到集合中最近的成员),然后再将其插入映射。不需要自定义哈希函数或相等比较。

请注意,
epsilon
本身不是一个很好的相等测试,例如,请参阅Re“浮点值不能通过==”进行比较-它们可以。您的“几乎相等”函数有一个可怕的特性:它是不可传递的。如果
a
“几乎等于”
b
b
“几乎等于”
c
,你就不能得出
a
“几乎等于”
c
的结论。你的地图查询会给你非常混乱的答案。
auto isEqual = [](const double& a, const double& b) {
  return fabs(a-b) <= numeric_limits<double>::epsilon();
};

unordered_map<double, int, hash<double>, decltype(isEqual)> m(0, hash<double>(), isEqual);
m[1/(double)3]++;
cout << m[1-2/(double)3] << endl; // expected 1, but zero

// -----------------------------

auto comp = [&](const double& a, const double& b) {
  if (isEqual(a, b)) return false;
  return a < b;
};

map<double, int, decltype(comp)> m2(comp);
m2[1/(double)3]++;
cout << m2[1-2/(double)3] << endl;  // expected and answered 1