哈希任意precision价值(提高::多precision :: cpp_int) [英] Hash an arbitrary precision value (boost::multiprecision::cpp_int)
问题描述
我需要得到的任意precision(从Boost.Multi precision)值的哈希;我使用 cpp_int
后端。现在,我想出了以下code:
I need to get the hash of value with arbitrary precision (from Boost.Multiprecision); I use the cpp_int
backend. For now, I came up with the following code:
boost::multiprecision::cpp_int x0 = 1;
const auto seed = std::hash<std::string>{}(x0.str());
我不需要code要尽可能快,但我觉得很笨拙散列字符串重新presentation。
I don't need the code to be as fast as possible, but I find it very clumsy to hash the string representation.
所以我的问题是双重的:
So my question is twofold:
- 保持任意precision,我可以更有效地散列值?
- 也许我不应该坚持保持任意precision,我应该转换为
双击
,我可以很容易地散列(我仍然但是制作所需要的比较使用任意precision价值? 哈希表)
- Keeping the arbitrary precision, can I hash the value more efficiently?
- Maybe I should not insisting on keeping the arbitrary precision and I should convert to a
double
which I could hash easily (I would still however making the comparison needed for the hash table using the arbitrary precision value)?
推荐答案
您可以(AB)使用序列化支持:
You can (ab)use the serialization support:
有关序列化支持有两种形式:
类数量
, debug_adaptor
, logged_adaptor
和 rational_adaptor
的通过序列化支持,需要底层的后端可序列化。
Support for serialization comes in two forms: Classes
number
,debug_adaptor
,logged_adaptor
andrational_adaptor
have "pass through" serialization support which requires the underlying backend to be serializable.
后端 cpp_int
, cpp_bin_float
, cpp_dec_float
和 float128
必须为Boost.Serialization&nbsp全力支持。
Backends cpp_int
, cpp_bin_float
, cpp_dec_float
and float128
have full support for Boost.Serialization.
那么,让我凑齐一起的东西与升压和std无序容器作品:
So, let me cobble something together that works with boost and std unordered containers:
template <typename Map>
void test(Map const& map) {
std::cout << "\n" << __PRETTY_FUNCTION__ << "\n";
for(auto& p : map)
std::cout << p.second << "\t" << p.first << "\n";
}
int main() {
using boost::multiprecision::cpp_int;
test(std::unordered_map<cpp_int, std::string> {
{ cpp_int(1) << 111, "one" },
{ cpp_int(2) << 222, "two" },
{ cpp_int(3) << 333, "three" },
});
test(boost::unordered_map<cpp_int, std::string> {
{ cpp_int(1) << 111, "one" },
{ cpp_int(2) << 222, "two" },
{ cpp_int(3) << 333, "three" },
});
}
让我们将相关的散&LT;&GT;
实现我们自己的 hash_impl
专业化,使用多precision 和的序列化:
Let's forward the relevant hash<>
implementations to our own hash_impl
specialization that uses Multiprecision and Serialization:
namespace std {
template <typename backend>
struct hash<boost::multiprecision::number<backend> >
: mp_hashing::hash_impl<boost::multiprecision::number<backend> >
{};
}
namespace boost {
template <typename backend>
struct hash<multiprecision::number<backend> >
: mp_hashing::hash_impl<multiprecision::number<backend> >
{};
}
现在,当然,这引出了一个问题,如何 hash_impl
实施?
Now, of course, this begs the question, how is hash_impl
implemented?
template <typename T> struct hash_impl {
size_t operator()(T const& v) const {
using namespace boost;
size_t seed = 0;
{
iostreams::stream<hash_sink> os(seed);
archive::binary_oarchive oa(os, archive::no_header | archive::no_codecvt);
oa << v;
}
return seed;
}
};
这看起来pretty简单。这是因为升压是真棒,续写 hash_sink
设备与升压用IOSTREAMS只是下面的简单练习:
This looks pretty simple. That's because Boost is awesome, and writing a hash_sink
device for use with Boost Iostreams is just the following straightforward exercise:
namespace io = boost::iostreams;
struct hash_sink {
hash_sink(size_t& seed_ref) : _ptr(&seed_ref) {}
typedef char char_type;
typedef io::sink_tag category;
std::streamsize write(const char* s, std::streamsize n) {
boost::hash_combine(*_ptr, boost::hash_range(s, s+n));
return n;
}
private:
size_t* _ptr;
};
完整演示:
<大骨节病> 住在Coliru 骨节病>
#include <iostream>
#include <iomanip>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_int/serialize.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/functional/hash.hpp>
namespace mp_hashing {
namespace io = boost::iostreams;
struct hash_sink {
hash_sink(size_t& seed_ref) : _ptr(&seed_ref) {}
typedef char char_type;
typedef io::sink_tag category;
std::streamsize write(const char* s, std::streamsize n) {
boost::hash_combine(*_ptr, boost::hash_range(s, s+n));
return n;
}
private:
size_t* _ptr;
};
template <typename T> struct hash_impl {
size_t operator()(T const& v) const {
using namespace boost;
size_t seed = 0;
{
iostreams::stream<hash_sink> os(seed);
archive::binary_oarchive oa(os, archive::no_header | archive::no_codecvt);
oa << v;
}
return seed;
}
};
}
#include <unordered_map>
#include <boost/unordered_map.hpp>
namespace std {
template <typename backend>
struct hash<boost::multiprecision::number<backend> >
: mp_hashing::hash_impl<boost::multiprecision::number<backend> >
{};
}
namespace boost {
template <typename backend>
struct hash<multiprecision::number<backend> >
: mp_hashing::hash_impl<multiprecision::number<backend> >
{};
}
template <typename Map>
void test(Map const& map) {
std::cout << "\n" << __PRETTY_FUNCTION__ << "\n";
for(auto& p : map)
std::cout << p.second << "\t" << p.first << "\n";
}
int main() {
using boost::multiprecision::cpp_int;
test(std::unordered_map<cpp_int, std::string> {
{ cpp_int(1) << 111, "one" },
{ cpp_int(2) << 222, "two" },
{ cpp_int(3) << 333, "three" },
});
test(boost::unordered_map<cpp_int, std::string> {
{ cpp_int(1) << 111, "one" },
{ cpp_int(2) << 222, "two" },
{ cpp_int(3) << 333, "three" },
});
}
打印
void test(const Map&) [with Map = std::unordered_map<boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<> >, std::basic_string<char> >]
one 2596148429267413814265248164610048
three 52494017394792286184940053450822912768476066341437098474218494553838871980785022157364316248553291776
two 13479973333575319897333507543509815336818572211270286240551805124608
void test(const Map&) [with Map = boost::unordered::unordered_map<boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<> >, std::basic_string<char> >]
three 52494017394792286184940053450822912768476066341437098474218494553838871980785022157364316248553291776
two 13479973333575319897333507543509815336818572211270286240551805124608
one 2596148429267413814265248164610048
正如你所看到的,Boost的之间实施的差别标准库的 unordered_map
在相同的哈希值不同的排序显示。
As you can see, the difference in implementation between Boost's and the standard library's unordered_map
show up in the different orderings for identical hashes.
这篇关于哈希任意precision价值(提高::多precision :: cpp_int)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!