【问题标题】:Why do all my items go to unordered_map bucket 0?为什么我的所有物品都进入 unordered_map 存储桶 0?
【发布时间】:2021-09-24 18:10:12
【问题描述】:

这是我对 hashmap 的分析中的日志(截断):

unsigned nbuckets = octree->Nodes.bucket_count();

LOG(Error, "bucket size = {0}, kk = {1}", nbuckets, octree->Nodes.max_load_factor());

for (auto& x : octree->Nodes) {
   LOG(Warning, "Element [{0}:{1}] is in bucket {2}", x.first.morton, x.second.position, octree->Nodes.bucket(x.first));
}
[ 00:19:26.169 ]: [Error] bucket size = 512, kk = 1.0
[ 00:19:26.169 ]: [Warning] Element [132120576:X:384 Y:384 Z:384] is in bucket 0
[ 00:19:26.169 ]: [Warning] Element [115343360:X:128 Y:384 Z:384] is in bucket 0
[ 00:19:26.169 ]: [Warning] Element [98566144:X:384 Y:128 Z:384] is in bucket 0
[ 00:19:26.169 ]: [Warning] Element [81788928:X:128 Y:128 Z:384] is in bucket 0
[ 00:19:26.169 ]: [Warning] Element [65011712:X:384 Y:384 Z:128] is in bucket 0
[ 00:19:26.169 ]: [Warning] Element [48234496:X:128 Y:384 Z:128] is in bucket 0
[ 00:19:26.169 ]: [Warning] Element [31457280:X:384 Y:128 Z:128] is in bucket 0
[ 00:19:26.169 ]: [Warning] Element [16515072:X:192 Y:192 Z:192] is in bucket 0
[ 00:19:26.169 ]: [Warning] Element [14417920:X:64 Y:192 Z:192] is in bucket 0
[ 00:19:26.169 ]: [Warning] Element [12320768:X:192 Y:64 Z:192] is in bucket 
....

地图是这样定义的:

std::unordered_map<Int3Pos, OctreeNode, Int3Pos::HashFunction> Nodes;

其中 OctreeNode 是具有一些值的结构。和 Int3Pos:

struct Int3Pos // TODO rename
{
public:
    Int3_64 position;
    uint64 morton;

    Int3Pos() : position(Int3_64(0, 0, 0)), morton(0) { }
    Int3Pos(Int3_64 c)
    {
        this->position = c;
        this->morton = mrtn(this->position);
    }

    bool operator==(const Int3Pos& otherPos) const
    {
        if (this->morton == otherPos.morton) return true;
        else return false;
    }

    struct HashFunction
    {
        size_t operator()(const Int3Pos& pos) const
        {
            return pos.morton;
        }
    };
};

它告诉了 512 个桶,但都变成了 0。或者我误解了什么?

【问题讨论】:

  • 可能你的散列函数总是为每个对象返回相同的值。您确定每个对象的morton 都不同吗?否则,您应该发布minimal reproducible example
  • if(condition) return true; else return false; 可以是return condition;
  • @FrançoisAndrieux 是的,您可以在 LOG 中看到不同的整数。我确定。我添加了日志打印代码。
  • 什么是nbuckets?和Nodes有关系吗?
  • 这里没有足够的信息来帮助您解决问题。显示的行为很奇怪。您需要分享minimal reproducible example 以提供更多信息。

标签: c++ hashmap


【解决方案1】:

您的哈希函数非常糟糕。您显示的莫顿值的最大公约数是

GCD(132120576, 115343360, 98566144, 81788928, 65011712, 48234496, 31457280, 16515072, 14417920, 12320768) = 2^18 = 262144

除以 512。所有值都进入(第一个)存储桶 0。

你可以试试

return pos.morton % 511;  // or pos.morton % 1023, or std::hash<decltype(pos.morton)>{}(pos.morton).

【讨论】:

  • 512除以什么,怎么去0桶?
  • 所有显示的哈希值除以桶数 512。您想了解如何实现哈希映射,如何选择桶。
【解决方案2】:

看来您使用的是 MSVC 实现,它使用两种大小的unordered_map 的幂。其他一些实现更喜欢原始大小。

二次幂的优势是快速存储桶访问。可以使用&amp; 运算(按位与)代替% 运算(模数)。

prime-sized 的优点是可以容忍像你这样不太好的哈希函数。

如果您可以使用其他库,例如boost::unordered_map,您可以尝试一下,以避免依赖特定的 STL 细节。但更好的是改进散列函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    相关资源
    最近更新 更多