2017-05-10 2 views
1

나는 8 바이트 QByteArray을 가지고 있으며 그 배열의 특정 비트를 검사해야하지만 매번 같은 비트는 검사하지 않아야합니다. 8 바이트 배열을 구성하는 64 비트 중 하나 일 수 있습니다. 성능 우선 순위!QByteArray의 특정 비트 확인

현재의 메서드는 먼저 해당 배열에서 특정 바이트를 가져온 다음 특정 반 바이트 (또는 니블)를 가져온 다음 QByteArray::number(x, 2)을 사용하여 이진 표현으로 다른 QByteArray으로 변환 한 다음 마지막으로 비트를 검사합니다. 이것은 빤다. 나는 더 좋은 길을 원한다.

QBitArray에로드하여 특정 비트를 쉽고 빠르게 검색 할 수 있도록했습니다. 메모리에 표현 된 내용이 QByteArray 또는 quint64과 같으므로 변환이 허용되지만 변환이 허용되지 않습니다.

QByteArray의 특정 비트 (0 ~ 63)가 1 또는 0인지 빠르게 확인하려면 어떻게해야합니까?

+0

질문에 현재 코드를 추가하십시오. 왜 비트 연산자를 사용하여 비트 값을 알 수 없는지 궁금합니다. http://stackoverflow.com/a/523737/2266412 –

+0

그 이유는'int'를 받아 들여 원시 QByteArray 비트 검사를 찾고 있기 때문입니다. 먼저 비트가있는 특정 바이트를 찾고 int로 변환 한 다음 해당 메서드를 사용해야합니다. 바이트 위치와 비트 위치는 논리를 이해할 필요가있다. 성능이 중요하므로 더 직접적이고 더 빠른 것을 원합니다. 저는 현재 코드에 대해 설명했으며, 전혀 사용하지 않을 것입니다. 지저분해서 게시하는 것이 전혀 도움이되지 않을 것이라고 생각합니다. – mrg95

+0

당신이 말하는 "논리"는 현대 CPU에서는 사소한 것입니다. https : // godbolt로 이동해야합니다.org를 방문하여 직접 확인하십시오. –

답변

2

QBitArray은 다른 것으로 변환 할 수 있도록 설계되지 않았습니다. 내부 표현은 실제로 내부적입니다.

아아, 비트 검사는 비교적 쉽습니다. 현대 건축물은 배럴 쉬프터를 사용하므로 변속이 저렴합니다.

가능한 비트 - 바이트 매핑은 여러 가지가 있습니다. 의 그들 모두를 커버하자 따라서

 byte 0  byte 1  byte n-1 byte n 
LL - [] [89ABCDEF] ... 
LB - [] [FEDCBA98] ... 
BL -      ... [89ABCDEF] [] 
BB -      ... [FEDCBA98] [] 

:

enum class BitMapping { LL, LB, BL, BB }; 

bool getBit1(const QByteArray & arr, int bit, BitMapping m) { 
    Q_ASSERT(arr.size() >= 8); 
    auto byte = (m == BitMapping::LL || m == BitMapping::LB) ? 
       bit/8 : (7 - bit/8); 
    bit = (m == BitMapping::LB || m == BitMapping::BB) ? 
     (bit%8) : (7 - (bit%8)); 
    return arr.at(byte) & (1<<bit); 
} 

우리는 플랫폼은 64 비트 정수에 대한 합리적인 지원이 있다고 가정한다면, 우리는 그 활용 할 수 있습니다

bool getBit2(const QByteArray & arr, int bit, BitMapping m) { 
    Q_ASSERT(arr.size() >= 8); 
    auto value = *reinterpret_cast<const quint64 *>(arr.data()); 
    if (m == BitMapping::LL || m == BitMapping::BL) 
     bit = (bit & 0x38) + 7 - (bit & 0x07); // reorder bits 
    if ((Q_BYTE_ORDER == Q_LITTLE_ENDIAN && (m == BitMapping::BL || m == BitMapping::BB)) || 
     (Q_BYTE_ORDER == Q_BIG_ENDIAN && (m == BitMapping::LL || m == BitMapping::LB))) 
     bit = (bit & 0x07) + 0x38 - (bit & 0x38); // reorder bytes 
    return value & (1<<bit); 
} 

하나를 알맞은 컴파일러는 위의 두 가지 구현 모두를 전문화 할 때 인라인 할 것이다.

bool getBit(const QByteArray & arr, int bit) { 
    return getBit2(arr, bit, BitMapping::LB); 
} 

또한 LB 경우에 손으로 전문 수 있습니다 다음 Q_BYTE_ORDER 검사가 컴파일시 일정하고 어떤 런타임 오버 헤드가 발생 없다는 것을

bool getBit1(const QByteArray & arr, int bit) { 
    Q_ASSERT(arr.size() >= 8); 
    auto byte = bit/8; 
    bit = bit%8; 
    return arr.at(byte) & (1<<bit); 
} 

bool getBit2(const QByteArray & arr, int bit) { 
    Q_ASSERT(arr.size() >= 8); 
    auto value = *reinterpret_cast<const quint64 *>(arr.data()); 
    if (Q_BYTE_ORDER == Q_BIG_ENDIAN) 
     bit = (bit & 0x07) + 0x38 - (bit & 0x38); // reorder bytes 
    return value & (1<<bit); 
} 

참고.

getBit1getBit2 Qt를가 실행되는 모든 플랫폼에 이식하고, getBit2getBit1보다 조금 더 나은 코드를 생성합니다. x86-64에서 getBit2의 비트 트위 들링 코드는 5 명령어 수입니다.

mov $0x1,%eax 
shl %cl,%eax 
cltq 
test %rax,(%rdi) 
setne %al 
retq 
+0

LL, LB 등이 무엇을 의미하는지 혼란 스럽습니까? 당신은 명확히 할 수 있습니까? – mrg95

+0

이들은 바이트 배열의 비트 순서를 나타냅니다. 가능한 네 가지 순서가 있습니다. 그들은 그래픽으로 설명됩니다. 뭐가 불분명하니? –

+0

글쎄, 처음에는 L과 B가 무엇을 의미하는지. 나는 Little과 Big을 가정하지만 LL와 LB의 처음 8 비트가 같지 않다는 것을 알게되면 혼란스러워집니다. – mrg95