가장 빠른 방법은 무엇입(s)루프를 통해 데이터 큰 덩어리를 개별적
-
03-07-2019 - |
문제
나를 통해 실행하는 메모리 블록의 이진 데이터 바이트다.
현재 내가 뭔가를 하는 다음과 같다:
for (i = 0; i < data->Count; i++)
{
byte = &data->Data[i];
((*byte & Masks[0]) == Masks[0]) ? Stats.FreqOf1++; // syntax incorrect but you get the point.
((*byte & Masks[1]) == Masks[1]) ? Stats.FreqOf1++;
((*byte & Masks[2]) == Masks[2]) ? Stats.FreqOf1++;
((*byte & Masks[3]) == Masks[3]) ? Stats.FreqOf1++;
((*byte & Masks[4]) == Masks[4]) ? Stats.FreqOf1++;
((*byte & Masks[5]) == Masks[5]) ? Stats.FreqOf1++;
((*byte & Masks[6]) == Masks[6]) ? Stats.FreqOf1++;
((*byte & Masks[7]) == Masks[7]) ? Stats.FreqOf1++;
}
는 마스크:
for (i = 0; i < 8; i++)
{
Masks[i] = 1 << i;
}
(어떻게 든 관리하지 않았으로 그것을 할 수 있는 빠른 루프에서 또는 인라인 함수,그래서 나는 그것을 썼습니다.)
누군가는 방법에 대한 제안을 개선하는 첫 번째 루프?내가 오히려 경험을 가진을 받고 내려 비트입니다.
이처럼 보일 수도 있 바보 같은 일을 하는 것입니다.하지만 내가를 구현하는 과정에서 압축 알고리즘이 있습니다.내가 원하는 비트에 액세스하는 부분을 아래로 오른쪽.
감사합니다!
PS:이것은 Visual Studio2008 컴파일러입니다.그래서 그것은 좋은 것입하는 경우 제안을 적용하는 컴파일러입니다.
PPS:나는 그냥 깨달아,내가 증가할 필요가 없랍니다.하나는 것 충분하다.그 차이를 계산하는 총 비트입니다.그러나는 것이 특정 단 계산합니다.내가 정말 원하는 빠른 수행은 조금 추출합니다.
편집:조회 테이블 아이디어는 앞으로 좋은 것입니다.나는 깨닫지만 내가 질문을 제기된 제목입니다.기 때문에 무슨 말 하고 싶지 않은 수를 비트이지만,서로 액세스 비트입니다.
다른 편집:그것은 가능한 발전에 의해 포인터를 하나의 비트는 데이터가?
다른 편집:모든 주셔서 감사합니다 당신의 답변이 지금까지.
내가 무엇을 구현하려면 다음 단계에서는 nonsophisticated binary arithmetic coder 하지 않는 분석이 있다.그래서 나에만 관심이 있는 단일 비트니다.결국 그것이 될 것이다 Context-adaptive BAC 그러나 나는 그것을 떠날 것입니다.
가공 4 바이트를 1 대신 바이트 될 수 있습니다.그러나 루프 32 비트 이상의 비용이 많이 드는뿐만 아니라,그렇지 않나요?
해결책
지 않았다 정말 이해 당신이 무엇을 행하려고 노력하는 것입니다.하지만 경우에 당신은 단지에 접근하고자 하는 비트 비트맵에,당신은 이러한 사용할 수 있습니다(이 검증되지 않은!!!) 기능:
#include <stddef.h>
_Bool isbitset(unsigned char * bitmap, size_t idx)
{
return bitmap[idx / 8] & (1 << (idx % 8)) ? 1 : 0;
}
void setbit(unsigned char * bitmap, size_t idx)
{
bitmap[idx / 8] |= (1 << (idx % 8));
}
void unsetbit(unsigned char * bitmap, size_t idx)
{
bitmap[idx / 8] &= ~(1 << (idx % 8));
}
void togglebit(unsigned char * bitmap, size_t idx)
{
bitmap[idx / 8] ^= (1 << (idx % 8));
}
편집: Ok,I 생각 이해 당신이 무엇을 하고 싶:빠르고 반복을 통해 시퀀스의 비트입니다.따라서,우리가 사용하고 싶지 않은 랜덤 액세스 기능이 위에서만 읽고 전체의 말씀 데이터를 한꺼번에.
당신이 하나를 사용할 수 있습니다 unsigned integer 유형은 당신처럼,하지만 당신은 선택해야 하는 가능성에 해당하는 단어의 크기를 포함됩니다.제가 갈게요 uint_fast32_t
서 stdint.h
:
uint_fast32_t * data = __data_source__;
for(; __condition__; ++data)
{
uint_fast32_t mask = 1;
uint_fast32_t current = *data;
for(; mask; mask <<= 1)
{
if(current & mask)
{
// bit is set
}
else
{
// bit is not set
}
}
}
에서 내부 루프 설정할 수 있는 비트와
*data |= mask;
unset 비트와
*data &= ~mask;
와 전환을 가진 비
*data ^= mask;
경고: 코드에 예기치 않게 동작할 수 있습니다 on-endian 아키텍처!
다른 팁
가장 빠른 방법은 아마도 바이트 값의 조회 테이블과 해당 바이트의 비트 수를 구축하는 것입니다. 적어도 Google에서 인터뷰 할 때 답이되었습니다.
수십 가지 비트 관련 제품에 대한 다음 링크를 참조하십시오. 비트 twiddling 핵
각 바이트 값 (256)을 1의 수에 매핑하는 테이블을 사용하십시오. (0의 #은 단지 (8 - # of 1)입니다. 그런 다음 바이트를 반복하고 여러 조회 및 비교 대신 각 바이트에 대해 단일 조회를 수행하십시오. 예를 들어:
int onesCount = 0;
for (i = 0; i < data->Count; i++)
{
byte = &data->Data[i];
onesCount += NumOnes[byte];
}
Stats.FreqOf1 += onesCount;
Stats.FreqOf0 += (data->Count * 8) - onesCount;
미리 계산 된 조회 테이블을 사용할 수 있습니다.
static int bitcount_lookup[256] = { ..... } ; /* or make it a global and compute the values in code */
...
for( ... )
byte = ...
Stats.FreqOf1 += bitcount_lookup[byte];
다음은 32 비트 정수의 1 비트를 계산하는 방법입니다 (Java의 기반 Integer.bitCount(i)
방법):
unsigned bitCount(unsigned i) {
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
i = (i + (i >> 4)) & 0x0f0f0f0f;
i = i + (i >> 8);
i = i + (i >> 16);
return i & 0x3f;
}
따라서 데이터를 INT에 캐스트하고 4 바이트 단계로 앞으로 나아갈 수 있습니다.
여기에 단일 32 비트 값으로 채찍질 한 간단한 것이 있지만, 여러 비트에 적응하기가 어렵지 않을 것입니다 ....
int ones = 0;
int x = 0xdeadbeef;
for(int y = 0;y < 32;y++)
{
if((x & 0x1) == 0x1) ones++;
x = (x >> 1);
}
printf("%x contains %d ones and %d zeros.\n", x, ones, 32-ones);
그러나 프로세스의 값을 수정합니다. 보관 해야하는 데이터 에서이 작업을 수행하는 경우 먼저 사본을 만들어야합니다.
__Ams 에서이 작업을 수행하는 것은 아마도 더 나을 것입니다. 아마도 더 빠를 수도 있지만 컴파일러가 얼마나 잘 최적화 할 수 있는지 말하기는 어렵습니다 ...
각 솔루션마다 고려하면 각 솔루션에는 단점이 있습니다. 조회 테이블 또는 비트 시프터 (광산과 같은)에는 모두 단점이 있습니다.
래리
ttobiass - 인라인 기능은 당신이 말하는 것과 같은 응용 프로그램에서 중요하지만, 명심해야 할 것들이 있습니다. 너 할 수 있다 인라인 코드에서 성능을 얻으십시오. 몇 가지를 기억하십시오.
- 디버그 모드의 인라인은 존재하지 않습니다. (당신이 그것을 강요하지 않는 한)
- 컴파일러는 적합하다고 생각되는 기능을 인라인으로 작동합니다. 종종 기능을 인라인으로 말하면 전혀 수행하지 않을 수 있습니다. __forceinline을 사용하더라도. 인라인에 대한 자세한 내용은 MSDN을 확인하십시오.
- 특정 기능 만 감소 할 수도 있습니다. 예를 들어 재귀 기능을 인화 할 수 없습니다.
C/C ++ 언어에 대한 프로젝트 설정에서 최상의 성능을 얻을 수 있으며 코드를 구성하는 방법. 이 시점에서 힙 대 스택 작업, 컨벤션 호출, 메모리 정렬 등을 이해하는 것이 중요합니다.
나는 이것이 당신의 질문에 정확히 답하지는 않지만, 당신은 성능과 최고의 성능을 얻는 방법을 언급하며, 이러한 것들이 핵심입니다.
링크 마차에 가입하려면 :계산 비트
이것이 조기 최적화의 경우가 아니고 마지막 펨토초마다 진정으로 짜야한다면, 각 바이트 값의 비트 카운트로 한 번 채우는 256 요소 정적 배열이 더 나을 것입니다.
stats.freqof1 += bitcounttable [byte
그리고 루프가 완료되면 :
stats.freqof0 = ((data-> count * 8) -STATS.FREQOF1)
책에 이것에 대한 다른 기술에 대한 전체 장이 있습니다. 아름다운 코드. Google 도서에서 읽을 수 있습니다 (대부분) 여기에서 시작합니다.
비트를 추출하는 더 빠른 방법은 사용하는 것입니다.
bitmask= data->Data[i];
while (bitmask)
{
bit_set_as_power_of_two= bitmask & -bitmask;
bitmask&= bitmask - 1;
}
비트 세트를 계산하려면 캐시 당 LUT가 빠르지 만 인터리브 비트 계산 방법으로 일정한 시간에도 할 수 있습니다. 이 답변의 링크.