2013-10-03 1 views
5

것은 내가 vector<char>을 가지고 있고이 벡터 내에서 비트의 범위에서 부호없는 정수를 얻을 수 있어야합니다. 예 :비트 내부`표준에서 정수를 가져 오기 : 벡터 <char>`

visualisation of bitvalues

내가 원하는 출력을 얻을 수있는 올바른 쓰기 작업을 할 수없는 것. 내 의도 된 알고리즘은 다음과 같이 진행한다 : (0xff >> unused bits in byte on the left)

  • << 결과와 첫번째 바이트가 출력 된 바이트 수를 왼쪽
    • &

      * 최종 출력 바이트
    • |이 비트 수
    • 다음 바이트마다 :
      • << 바이트 단위로 남은 비트
      • 012 3,516,
      • | 최종 출력
      • >>과 최종 출력
    • | (시프트되지 않은) 최종 바이트, 바이트 오른쪽
    의 바이트에 사용되지 않는 비트들의 수에 의해 최종 출력

    #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,16,32 또는 64 비트
  • 을 wside 수 반환하는 정수 긴 8 비트가

  • 답변

    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_i가 끝에서 떨어져있는 바이트 수이기도합니다. 값 byte_width - byte_i은 의미 론적 의미가 없습니다 (하나는 델타이고 다른 하나는 인덱스 임)

    나머지 코드는 문제가 없습니다. 이 알고리즘에는 두 가지 문제가 있습니다.

    먼저 비트를 누적하기 위해 결과 유형을 사용할 때 왼쪽에 여유 공간이 있다고 가정합니다. 오른쪽 경계 근처에 비트가 설정되어 있고 범위를 선택하면 비트가 이동됩니다. 예를 들어, 당신은 비트 문자열 00000000 00101010 올바른 결과는 비트 문자열 11010000 00101010와 53290입니다에 해당하는 결과 (42)를 얻을 수 있습니다

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

    실행 해보십시오. 가장 오른쪽에있는 4 비트가 어떻게 제로화되었는지 주목하십시오.이는 value 변수가 지나치게 많아지기 시작하여 4 비트가 변수 밖으로 이동되도록하기 때문입니다. 끝에서 뒤로 이동하면 비트가 0으로됩니다.

    두 번째 문제는 끝에 오른쪽 이동과 관련이 있습니다. value 변수의 오른쪽 끝이 오른쪽 끝의 오른쪽 시프트 이전에 1이되고 템플릿 매개 변수가 부호있는 유형이면 오른쪽 시프트는 '산술'오른쪽 시프트입니다. 1 칸 채워져 부정확 한 부정 값을 남깁니다.

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

    예상되는 결과는 비트 문자열 00011011 01000000로 6976을해야하지만, 현재 구현은 비트 문자열 11111011 01000000과 -1216을 반환

    예, 실행 해보십시오.

    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

    이 코드는'bits.get_bits에 대해 작동하지 않는다. (0, 32) ; - 예상 한'519053860746' 대신 0을 반환합니다 – Ell

    +0

    맞습니다. 이 버그는 그 결과가 마지막에 가려지는 방식 때문입니다. 왼쪽으로 이동하면 비트 마스크가 0으로 바뀌어 의미가 없어집니다. 수정 사항을 추가했습니다. – Cookyt

    0

    흥미로운 문제. 비슷한 일을했는데 일부 시스템에서는 작동합니다.

    • 귀하의 문자는 8 비트입니다? 아니면 16? 정수가 얼마나 큽니까? 32 또는 64?
    • 가 1 분 동안 벡터의 복잡성을 무시합니다.
    • 비트 단지 어레이로서 생각해.
    • 얼마나 많은 비트를해야합니까? 당신은 8 * 수의 문자를 가지고 있습니다.
    • 시작 문자, 추출 할 비트 수, 종료 문자, 그곳의 비트 수, 중간에있는 문자 수를 계산해야합니다.
    • 당신은 당신이 필요합니다
    • 비트 및 &를 마지막 부분 문자의 첫 번째 부분 문자에 대한 비트 및 &가 필요합니다
    • 당신은 왼쪽 편이 < < (또는 오른쪽 시프트를 >>)가 필요합니다, 어떤 순서로 시작 하느냐에 따라 달라집니다.
    • Integer의 엔디안은 무엇입니까? 당신이 bitIndex의/char_bit_width 당신의 배열에 인덱스를 계산합니다 어느 시점에서

    , 당신은 당신의 char_bit_width로 당신의 bitIndex의 같은 값 (171), 8을 준, 그래서 당신은 계산이 유용한 값으로 종료됩니다 :

    첫번째 바이트
    • 8분의 171은 = 23 // 위치
    • 171퍼센트 8 = 제 숯/3 바이트 // 비트
    • 8 - 8 = 1백71퍼센트 마지막 문자의 비트 // 5/바이트
    • sizeof (정수) = 4
    • 를 sizeof (정수) + ((1백71% 8)> 0 1 : 0) // 얼마나 많은 배열 위치

    필요한 일부 어셈블리를 검사 할 ...

    0

    한 가지 당신이 확실히있다 내가 생각한 것 : 당신이 벡터에서 비트를 인덱싱하는 방식은 당신이 문제에서 제시 한 것과는 다르다. 나는. 알고리즘을 사용하면 비트의 순서는 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 | 23 22 21 ...과 같습니다. 솔직히, 나는 당신의 전체 알고리즘을 읽지는 않았지만, 이것은 첫 단계에서 빠졌습니다.