如何编写和调用 std::hash? - 对于 gmp 的 mpz_class 和 mpz_t

Posted

技术标签:

【中文标题】如何编写和调用 std::hash? - 对于 gmp 的 mpz_class 和 mpz_t【英文标题】:How to write and call std::hash? - for gmp's mpz_class and mpz_t 【发布时间】:2020-06-18 14:46:25 【问题描述】:

我认为大部分工作都在这里完成,最后缺少一点细节。继续阅读。

我正在尝试编写胶水代码,用于使用MurmurHash3 散列 C++ 中 GMP 库的大整数(mpz_tmpz_class)。我这样做是为了以后在std::unordered_map<mpz_class, int> 中使用它们。

我希望代码能够以有用的方式编译 32 位和 64 位系统,并且在需要 128 位系统时易于扩展。为此我编写了MurmurHash3_size_t() 函数,它调用MurmurHash3 的正确哈希函数,然后将结果转换为size_t。我假设size_t 在 32/64/128 位系统方面具有正确的位大小。 (我不知道这个假设是否有用。)这部分代码编译得很好。

当我想定义std::hash 函数时,问题就出现了。我的代码出现编译器错误(请参阅代码中的注释)。如何正确编写这些std::hash函数以及如何调用它们?

(click to view MurmurHash3.h)

文件hash_mpz.cpp

#include "hash_mpz.h"
#include <gmpxx.h>
#include "MurmurHash3.h"

size_t MurmurHash3_size_t(const void *key, int len, uint32_t seed) 

#if SIZE_MAX==0xffffffff
    size_t result;
    MurmurHash3_x86_32(key, len, seed, &result);
    return result;

#elif SIZE_MAX==0xffffffffffffffff
    size_t result[2];
    MurmurHash3_x64_128(key, len, seed, &result);
    return result[0] ^ result[1];

#else
#error cannot determine correct version of MurmurHash3, because SIZE_MAX is neither 0xffffffff nor 0xffffffffffffffff
#endif



namespace std 

size_t hash<mpz_t>::operator()(const mpz_t &x) const 
    // found 1846872219 by randomly hitting digits on my keyboard
    return MurmurHash3_size_t(x->_mp_d, x->_mp_size * sizeof(mp_limb_t), 1846872219);


size_t hash<mpz_class>::operator()(const mpz_class &x) const 
    // compiler error in next statement
    // error: no matching function for call to ‘std::hash<__mpz_struct [1]>::operator()(mpz_srcptr)’
    return hash<mpz_t>::operator()(x.get_mpz_t());



【问题讨论】:

请随意评论目标系统的位大小的确定,因为我不确定什么是最好/最便携的方法。 C++ std::hash for GMP's big integer types mpz_class and mpz_t 页面可能会为您提供解决方案。虽然它不使用 murmurhash,但它提供了使用 C++17 的内置数据散列算法 string_view 散列 mpz_tmpz_class 的代码。 【参考方案1】:

找到适合我的解决方案:

namespace std 

size_t hash<mpz_srcptr>::operator()(const mpz_srcptr x) const 
    // found 1846872219 by randomly typing digits on my keyboard
    return MurmurHash3_size_t(x->_mp_d, x->_mp_size * sizeof(mp_limb_t),
            1846872219);


size_t hash<mpz_t>::operator()(const mpz_t &x) const 
    return hash<mpz_srcptr>  ((mpz_srcptr) x);


size_t hash<mpz_class>::operator()(const mpz_class &x) const 
    return hash<mpz_srcptr>  (x.get_mpz_t());



那么就可以使用hash函数如下:

#include <iostream>
#include <gmpxx.h>
#include <unordered_map>

#include "hash_mpz.h"

using namespace std;

int main() 
    mpz_class a;

    mpz_ui_pow_ui(a.get_mpz_t(), 168, 16);

    cout << "a      : " << a << endl;
    cout << "hash(a): " << (hash<mpz_class>  (a)) << endl;

    unordered_map<mpz_class, int> map;
    map[a] = 2;
    cout << "map[a] : " << map[a] << endl;

    return 0;

输出:

a      : 402669288768856477614113920779288576
hash(a): 11740158581999522595
map[a] : 2

欢迎评论。

【讨论】:

以上是关于如何编写和调用 std::hash? - 对于 gmp 的 mpz_class 和 mpz_t的主要内容,如果未能解决你的问题,请参考以下文章

如何为用户定义的类型专门化 std::hash<T>?

如何在大量无损压缩图像中提取重复的图像对(完全相同)?如何在内存中 std::hash?

生成blake2b哈希时崩溃

哈希<std::string> 与哈希<std::string_view>

std::hash 特化仍未被 std::unordered_map 使用

无法对指向成员的指针使用 std::hash 的特化?