c++ - एक अनियंत्रित सटीक मान को बढ़ावा दें(बढ़ावा:: बहुविकल्पी:: cpp_int)




c++11 boost (2)

मुझे मनमाने ढंग से परिशुद्धता के साथ मूल्य का हैश प्राप्त करने की आवश्यकता है (बूस्ट.मुलिप्ट्री से); मैं cpp_int बैकएंड का उपयोग करता cpp_int । अभी के लिए, मैं निम्नलिखित कोड लेकर आया हूं:

boost::multiprecision::cpp_int x0 = 1;
const auto seed = std::hash<std::string>{}(x0.str());

मुझे जितनी जल्दी हो सके कोड की आवश्यकता नहीं है, लेकिन मुझे स्ट्रिंग प्रतिनिधित्व को हैश करने के लिए बहुत ही भद्दा लगता है।

तो मेरा सवाल दुगना है:

  • मनमानी परिशुद्धता रखते हुए, क्या मैं मूल्य को अधिक कुशलता से प्राप्त कर सकता हूं?
  • हो सकता है कि मैं मनमानी परिशुद्धता रखने पर जोर नहीं दे रहा हूं और मुझे एक double बदलना चाहिए जो मैं आसानी से कर सकता हूं (मैं अभी भी मनमाना सटीक मूल्य का उपयोग करके हैश तालिका के लिए आवश्यक तुलना कर रहा हूं)?

आप (ab) क्रमांकन समर्थन का उपयोग कर सकते हैं:

क्रमांकन के लिए समर्थन दो रूपों में आता है: कक्षाएं number , debug_adaptor , logged_adaptor और rational_adaptor "क्रमांकन समर्थन" से गुजरती हैं जिसके लिए अंतर्निहित बैकएंड को क्रमबद्ध करने की आवश्यकता होती है।

बैकस्ट cpp_int , cpp_bin_float , cpp_dec_float और float128 में float128 का पूरा समर्थन है।

तो, मुझे एक साथ कुछ करने के लिए बढ़ावा देने और unordered कंटेनरों एसटीडी के साथ काम करता है:

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" },
    });
}

आइए प्रासंगिक hash<> हमारे अपने hash_impl स्पेशलाइजेशन के लिए कार्यान्वयन करें जो hash_impl और सीरियलाइजेशन का उपयोग करता है:

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 कैसे लागू किया गया है?

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;
    }
};

यह बहुत आसान लग रहा है। ऐसा इसलिए है क्योंकि बूस्ट भयानक है, और बूस्ट आईस्ट्रीम के साथ उपयोग के लिए एक hash_sink डिवाइस लिखना केवल निम्नलिखित सरल विकल्प है:

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;
};

पूर्ण डेमो:

कोलिरु पर रहते हैं

#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

जैसा कि आप देख सकते हैं, बूस्ट और मानक पुस्तकालय के unordered_map बीच कार्यान्वयन में अंतर समान हैश के लिए अलग-अलग unordered_map दिखाई देता है।


सिर्फ यह कहने के लिए कि मैंने अभी विकसित करने के लिए देशी हैशिंग समर्थन (Boost.Hash और std :: hash के लिए) जोड़ा है। यह सभी प्रकारों के लिए काम करता है जिसमें GMP आदि शामिल हैं। दुर्भाग्य से वह कोड Boost-1.62 तक जारी नहीं किया जाएगा।

इसके बाद का उत्तर (एब) क्रमबद्धता समर्थन का उपयोग करता है, वास्तव में बेहद शांत और वास्तव में चालाक है;) हालांकि, यह काम नहीं करेगा यदि आप सिटीहैश जैसे वेक्टर-आधारित हैशर का उपयोग करना चाहते हैं, तो मैंने एक्सेस करके उस का उपयोग करने का एक उदाहरण जोड़ा सीधे डॉक्स पर अंग: https://htmlpreview.github.io/?https://github.com/boostorg/multiprecision/blob/develop/doc/html/boost_multiprecision/tut/hash.html या तो प्रत्यक्ष अंग-अभिगम या क्रमांकन टिप पाठ्यक्रम के पिछले सभी रिलीज के साथ काम करेगा।





arbitrary-precision