2013-10-03 9 views
5

मेरे पास vector<char> है और मैं वेक्टर के भीतर बिट्स की एक श्रृंखला से एक हस्ताक्षरित पूर्णांक प्राप्त करने में सक्षम होना चाहता हूं। जैसेबिट्स से इंटीजर प्राप्त करें 'std :: vector <char> `

visualisation of bitvalues

और मैं सही संचालन लिखने के लिए वांछित आउटपुट प्राप्त करने के लिए सक्षम होने के लिए नहीं कर पा रहे। मेरे इरादा एल्गोरिथ्म इस प्रकार है:

  • &(0xff >> unused bits in byte on the left)
  • << परिणाम के साथ पहली बाइट उत्पादन बाइट की संख्या छोड़ दिया * एक बाइट
  • | इस अंतिम उत्पादन के साथ में बिट्स की संख्या
  • प्रत्येक बाद के बाइट के लिए:
    • << बाइट प्रति बाइट
    • 012 द्वारा छोड़ा गया
    • | अंतिम आउटपुट
    • >> साथ अंतिम आउटपुट
  • | अंतिम बाइट (स्थानांतरित कर दिया नहीं) के साथ इस बाइट अंतिम सही
पर बाइट में अप्रयुक्त बिट्स की संख्या से उत्पादन

#include <vector> 
#include <iostream> 
#include <cstdint> 
#include <bitset> 

template<class byte_type = char> 
class BitValues { 
    private: 
    std::vector<byte_type> bytes; 
    public: 
     static const auto bits_per_byte = 8; 
     BitValues(std::vector<byte_type> bytes) : bytes(bytes) { 
     } 
     template<class return_type> 
     return_type get_bits(int start, int end) { 
      auto byte_start = (start - (start % bits_per_byte))/bits_per_byte; 
      auto byte_end = (end - (end % bits_per_byte))/bits_per_byte; 
      auto byte_width = byte_end - byte_start; 
      return_type value = 0; 

      unsigned char first = bytes[byte_start]; 
      first &= (0xff >> start % 8); 
      return_type first_wide = first; 
      first_wide <<= byte_width; 
      value |= first_wide; 

      for(auto byte_i = byte_start + 1; byte_i <= byte_end; byte_i++) { 
       auto byte_offset = (byte_width - byte_i) * bits_per_byte; 
       unsigned char next_thin = bytes[byte_i]; 
       return_type next_byte = next_thin; 
       next_byte <<= byte_offset; 
       value |= next_byte; 
      } 
      value >>= (((byte_end + 1) * bits_per_byte) - end) % bits_per_byte; 

      return value; 
     } 
}; 

int main() { 
    BitValues<char> bits(std::vector<char>({'\x78', '\xDA', '\x05', '\x5F', '\x8A', '\xF1', '\x0F', '\xA0'})); 
    std::cout << bits.get_bits<unsigned>(15, 29) << "\n"; 
    return 0; 
} 
:

और यहाँ यह कोडिंग पर मेरे प्रयास है, जो सही परिणाम नहीं दे करता है

(कार्रवाई में: http://coliru.stacked-crooked.com/a/261d32875fcf2dc0)

मैं बस इन बिट मैनिप्लेशंस के आसपास अपने सिर को लपेटने के लिए प्रतीत नहीं कर सकता, और मुझे डिबगिंग बहुत मुश्किल लगता है! अगर कोई उपरोक्त कोड को सही कर सकता है, या किसी भी तरह से मेरी मदद कर सकता है, तो इसकी सराहना की जाएगी!

संपादित करें:

  • मेरे बाइट्स 8 बिट लंबे
  • वापस जाने के लिए हो सकता है 8,16,32 या 64 बिट्स wside
  • पूर्णांक बड़ा endian में संग्रहित है पूर्णांक हैं

उत्तर

1

आपने दो प्राथमिक गलतियां की हैं। पहला यहां है:

first_wide <<= byte_width; 

आपको थोड़ी गिनती से स्थानांतरित किया जाना चाहिए, बाइट गिनती नहीं। सही कोड है:

first_wide <<= byte_width * bits_per_byte; 

दूसरी गलती यहाँ है:

auto byte_offset = (byte_width - byte_i) * bits_per_byte; 

यह होना चाहिए

auto byte_offset = (byte_end - byte_i) * bits_per_byte; 

कोष्टक में मूल्य सही से शिफ्ट करने के लिए बाइट की संख्या होने की जरूरत है, जो बाइट्स बाइट_ई की संख्या भी अंत से दूर है। मूल्य byte_width - byte_i का कोई अर्थपूर्ण अर्थ नहीं है (एक डेल्टा है, दूसरा एक सूचकांक है)

शेष कोड ठीक है। हालांकि, इस एल्गोरिदम के साथ दो मुद्दे हैं।

सबसे पहले, अपने परिणाम प्रकार का उपयोग बिट्स को जमा करने के लिए करते समय, आप मानते हैं कि आपके पास बाईं ओर अतिरिक्त जगह है। यह मामला नहीं है यदि सही सीमा के पास सेट बिट्स हैं और सीमा की पसंद बिट्स को स्थानांतरित करने का कारण बनती है। उदाहरण के लिए,

bits.get_bits<uint16_t>(11, 27); 

चल आप परिणाम 42 जो बिट श्रृंखला के 00000000 00101010 सही परिणाम बिट श्रृंखला के 11010000 00101010 साथ 53,290 है से मेल खाती है मिलेगा प्रयास करें। ध्यान दें कि सही 4 बिट्स कैसे शून्य हो गए।ऐसा इसलिए है क्योंकि आप अपने value चर को ओवरफिफ्ट करके शुरू करते हैं, जिससे वे चार बिट्स को चर के बाहर स्थानांतरित किया जा सकता है। अंत में वापस स्थानांतरित करते समय, इसका परिणाम बिट्स को शून्य से बाहर कर दिया जाता है।

दूसरी समस्या को अंत में सही बदलाव के साथ करना है। यदि value वैरिएबल का दायां थोड़ा अंत में सही शिफ्ट से पहले 1 होता है, और टेम्पलेट पैरामीटर एक हस्ताक्षरित प्रकार है, तो सही किया गया सही शिफ्ट एक 'अंकगणित' सही शिफ्ट है, जो बिट्स पर बिट्स का कारण बनता है 1-भरे होने का अधिकार, आपको गलत नकारात्मक मान छोड़कर।

उदाहरण के लिए, चलाने की कोशिश:

bits.get_bits<int16_t>(5, 21); 

अपेक्षित परिणाम बिट श्रृंखला के 00011011 01000000 साथ 6976 होना चाहिए, लेकिन वर्तमान कार्यान्वयन रिटर्न -1216 बिट श्रृंखला के 11111011 01000000 साथ।

template<class ReturnType> 
ReturnType get_bits(int start, int end) { 
    int max_bits = kBitsPerByte * sizeof(ReturnType); 
    if (end - start > max_bits) { 
    start = end - max_bits; 
    } 

    int inclusive_end = end - 1; 
    int byte_start = start/kBitsPerByte; 
    int byte_end = inclusive_end/kBitsPerByte; 

    // Put in the partial-byte on the right 
    uint8_t first = bytes_[byte_end]; 
    int bit_offset = (inclusive_end % kBitsPerByte); 
    first >>= 7 - bit_offset; 
    bit_offset += 1; 
    ReturnType ret = 0 | first; 

    // Add the rest of the bytes 
    for (int i = byte_end - 1; i >= byte_start; i--) { 
    ReturnType tmp = (uint8_t) bytes_[i]; 
    tmp <<= bit_offset; 
    ret |= tmp; 
    bit_offset += kBitsPerByte; 
    } 

    // Mask out the partial byte on the left 
    int shift_amt = (end - start); 
    if (shift_amt < max_bits) { 
    ReturnType mask = (1 << shift_amt) - 1; 
    ret &= mask; 
    } 
} 
+0

यह:

मैं इस के अपने कार्यान्वयन जो नीचे दाएं से बाएं से बिट श्रृंखला बनाता है, उनके सही स्थिति में बिट्स रखने तो साथ शुरू करने के लिए है कि उपरोक्त दो समस्याओं से बचा रहे हैं डाल दिया है हस्ताक्षर किए गए पूर्णांक के लिए बहुत अच्छा काम करता है धन्यवाद! मैं सिर्फ हस्ताक्षर किए गए पूर्णांक की जांच करने के मिनट में हूं - मैं पूरी तरह से * सुनिश्चित नहीं हूं कि 'get_bits (14, 22) 'के लिए मेरा वांछित आउटपुट क्या है! मैं जल्द ही उस पर अपडेट के साथ उम्मीद करूँगा, या अगर मुझे लगता है कि यह वांछित व्यवहार है, तो आपके लिए एक टिक मार्क :) – Ell

+0

ऐसा लगता है कि यह कोड 'बिट्स.get_बीट्स (0, 32) के लिए काम नहीं करता है। ; '- यह अपेक्षित' 519053860746' – Ell

+0

की बजाय शून्य लौटाता है आप सही हैं। बग अंत में मास्क किए जाने के तरीके के कारण है। बाएं शिफ्ट को थोड़ा सा महत्व देता है जिससे 0 का बिटमैस्क होता है। मैंने एक फिक्स जोड़ा है। – Cookyt

0

दिलचस्प समस्या। मैंने कुछ सिस्टम काम करने के लिए समान किया है।

  • आपका char 8 बिट चौड़ा है? या 16? आपका पूर्णांक कितना बड़ा है? 32 या 64?
  • एक मिनट के लिए वेक्टर जटिलता को अनदेखा करें।
  • इसके बारे में बिट्स की एक सरणी के रूप में सोचें।
  • आपके पास कितने बिट हैं? आपके पास 8 * संख्याओं की संख्या
  • आपको प्रारंभिक चार, निकालने के लिए बिट्स की संख्या, चार समाप्त करने, बिट्स की संख्या और बीच में वर्णों की संख्या की गणना करने की आवश्यकता है।
  • आप पहली बार आंशिक चार
  • आप की जरूरत बिटवाइज़-और & पिछले आंशिक चार के लिए होगा के लिए बिटवाइज़-और & की आवश्यकता होगी
  • आप करेंगे बाएं पारी < < (या सही-शिफ्ट >>) की जरूरत है,
  • से आप किस ऑर्डर से शुरू करते हैं, इस पर निर्भर करता है कि आपके इंटीजर का एंडियन-नेस क्या है?

आप अपने सरणी में एक सूचकांक कि है bitindex/char_bit_width की गणना करेगा कुछ बिंदु पर, आप अपने bitindex के रूप में मूल्य 171, और 8 अपने char_bit_width के रूप में दे दी है, ताकि आप गणना की इन उपयोगी मूल्यों के साथ खत्म हो जाएगा:

  • 171/8 = 23 // पहली बाइट के स्थान
  • 171% 8 = पहले चार/बाइट में 3 // बिट्स
  • 8 - 171% 8 = 5 // पिछले चार में बिट्स/बाइट
  • आकार (पूर्णांक) = 4
  • sizeof (पूर्णांक) + ((171% 8)> 0 1: 0) // कितने सरणी पदों की जांच करने के

कुछ विधानसभा आवश्यक ...

0

वहाँ एक बात आप निश्चित रूप से है याद किया मुझे लगता है: जिस तरह से आप वेक्टर में बिट्स को इंडेक्स करते हैं, उस समस्या से अलग है जो आपको समस्या में दिया गया है। अर्थात। आपके द्वारा उल्लिखित एल्गोरिदम के साथ, बिट्स का क्रम 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 | 23 22 21 ... जैसा होगा। वाकई, मैंने आपके पूरे एल्गोरिदम के माध्यम से नहीं पढ़ा, लेकिन यह पहले चरण में चूक गया था।