Создание большого буста unordered_map с помощью cpp_int

Я пишу некоторый код на c ++ для назначения класса, который требует работы с библиотекой с несколькими точностями, такими как boost. По сути, мне нужно создать хеш-таблицу с несколькими большими целыми числами, а затем найти определенное значение в этой таблице.

Когда я использую h, g, p, которые закомментированы — код работает отлично и очень быстро. Как только я переключаюсь на те, которые не закомментированы, в строке выдается исключение памяти: hash_str> :: iterator got = mp.find (lkp);
Я только начинаю с c ++ и почти уверен, что что-то не так, потому что это должно выполняться довольно быстро, даже с большими числами.

#include <boost/unordered_map.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/math/special_functions/pow.hpp>

using namespace std;
using namespace boost::multiprecision;

template <typename T>
struct hash_str
{
size_t operator()( const T& t ) const
{
return std::hash<std::string>()
( t.str() );
}
};

int main()
{
boost::unordered_map<cpp_int, cpp_int, hash_str<cpp_int>> mp;
//boost::unordered_map<hash_str<cpp_int>, cpp_int, hash_str<cpp_int>> mp;
cpp_int k;
cpp_int h( "3239475104050450443565264378728065788649097520952449527834792452971981976143292558073856937958553180532878928001494706097394108577585732452307673444020333" );
cpp_int g( "11717829880366207009516117596335367088558084999998952205599979459063929499736583746670572176471460312928594829675428279466566527115212748467589894601965568" );
//cpp_int g = 1010343267;
//cpp_int h = 857348958;
//cpp_int p = 1073676287;
cpp_int p( "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084171" );
int b = pow( 2, 20 );
cpp_int denom;
cpp_int inv = powm( g, p - 2, p );

//building a hash table of all values h/g^x1
for ( cpp_int x = 1; x < b; ++x )

{
// go through all 2^20 values up to b, calculate the function h/g^x1,
// then hash it to put into table

denom = powm( inv, x, p );
k = ( h *denom ) % p;
mp.insert( std::make_pair( k, x ) );}
cpp_int lkp;
for ( int v = 1; v < b; ++v )
{
//cpp_int gb = pow(g, b);
lkp = powm( g, v*b, p );
//looking for a match for g^b^x0 in map mp; when found we need to find x
//which is x1 and then calc 'x'
boost::unordered::unordered_map<cpp_int, cpp_int, hash_str<cpp_int>>::iterator got = mp.find( lkp );
// Check if iterator points to end of map or if we found our value
if ( got != mp.end() )
{
std::cout << "Element Found - ";
//std::cout << got->first << "::" << got->second << std::endl;
}
/*else
{
std::cout << "Element Not Found" << std::endl;
}*/
}
return 0;

}

На всякий случай вот исключение, которое я получаю:
Необработанное исключение в 0x768F2F71 в MiM.exe: исключение Microsoft C ++: boost :: exception_detail :: clone_impl> в ячейке памяти 0x0109EF5C.

2

Решение

Хеш-функция довольно ужасна, потому что она выделяет временную строку только для ее хеширования. Строка будет иметь длину в логах (битах) / логах (10).

Дело в том, что это относительно быстрый способ сравнить цифры. С таким дорогостоящим хешем лучше использовать обычный контейнер Tree (std :: map<> например).

  • Я не проверял ваши формулы (особенно вокруг h/g^x1 потому что я даже не уверен, что x представляет собой x1). Помимо этой проблемы,
  • Я думаю, что есть проблема с правильностью v * b переполнение емкости int, по крайней мере, если вы используете 32-битный целочисленный компилятор.

Я немного прибрался, и он работает

#include <boost/math/special_functions/pow.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/unordered_map.hpp>
#include <chrono>

namespace bmp = boost::multiprecision;
using namespace std::chrono_literals;
using Clock = std::chrono::high_resolution_clock;

template <typename T> struct hash_str {
size_t operator()(const T &t) const { return std::hash<std::string>()(t.str()); }
};

template <typename T> struct hash_bin {
size_t operator()(const T &t) const {
return boost::hash_range(t.backend().limbs(), t.backend().limbs()+t.backend().size());
}
};
int main() {
using bmp::cpp_int;
boost::unordered_map<cpp_int, cpp_int, hash_bin<cpp_int> > mp;
#if 1
cpp_int const h("32394751040504504435652643787280657886490975209524495278347924529719819761432925580738569379585531805328""78928001494706097394108577585732452307673444020333");
cpp_int const g("11717829880366207009516117596335367088558084999998952205599979459063929499736583746670572176471460312928""594829675428279466566527115212748467589894601965568");
cpp_int const p("13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690""031858186486050853753882811946569946433649006084171");
#else
cpp_int const g = 1010343267;
cpp_int const h = 857348958;
cpp_int const p = 1073676287;
#endif
int constexpr b   = 1 << 20;
cpp_int const inv = powm(g, p - 2, p);

{
auto s = Clock::now();

// building a hash table of all values h/g^x1
for (cpp_int x = 1; x < b; ++x) {
// go through [1, b), calculate the function h/g^x1,
// then hash it to put into table

cpp_int denom = powm(inv, x, p);
cpp_int k = (h * denom) % p;
mp.emplace(std::move(k), x);
}

std::cout << "Built map in " << (Clock::now() - s)/1.0s << "s\n";
}

{
auto s = Clock::now();

for (cpp_int v = 1; v < b; ++v) {
//std::cout << "v=" << v << " b=" << b << "\n";
// cpp_int gb = pow(g, b);
cpp_int const lkp = powm(g, v * b, p);

// looking for a match for g^b^x0 in map mp; when found we need to find x
// which is x1 and then calc 'x'
auto got = mp.find(lkp);

// Check if iterator points to end of map or if we found our value
if (got != mp.end()) {
std::cout << "Element Found - ";
//std::cout << got->first << " :: " << got->second << "\n";
}
}
std::cout << "Completed queries in " << (Clock::now() - s)/1.0s << "s\n";
}
}

Это работает в 1m4s для меня.

Built map in 24.3809s
Element Found - Completed queries in 39.2463s
...

С помощью hash_str вместо hash_bin занимает 1м13сек:

Built map in 30.3923s
Element Found - Completed queries in 42.488s
0

Другие решения

Других решений пока нет …