unsigned char型の「1」ビットの数をカウントするためのCコード

StackOverflow https://stackoverflow.com/questions/697978

  •  22-08-2019
  •  | 
  •  

質問

私はそれが明白でなければ、それが動作する理由として説明を必要とC.にunsigned char型に1つの数を返すためにCコードが必要です。私は、32ビットの数値のためのコードの多くを発見したが、unsigned char型のためにあまりいませんでした。

役に立ちましたか?

解決

同じコードはunsigned char型のために動作します。それらをテストするすべてのビットをループ。こののrel="noreferrer">

他のヒント

const unsigned char oneBits[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};

unsigned char CountOnes(unsigned char x)
{
    unsigned char results;
    results = oneBits[x&0x0f];
    results += oneBits[x>>4];
    return results
}

15を介し0は、各ニブルの結果を追加するためのビットの数を知っている配列がある。

HACKMEM の3つの動作で、このアルゴリズムは、(約翻訳ました)をC:

bits = (c * 01001001001ULL & 042104210421ULL) % 017;

ULLは、64ビット演算を強制することです。それが必要だ、かろうじて...この計算は、33ビット整数を必要とします。)

実際には、あなただけの8ビットをカウントしているので、あなたは、042104210021ULLと第2の定数を置き換えることができますが、それはのようにきれいに左右対称に見えるません。

これはどのように動作しますか? cのビット単位の考え、および(a + b) % c = (a % c + b % c) % c IFFその(a | b) == a + b、および(a & b) == 0を覚えています。

  (c * 01001001001ULL & 042104210421ULL) % 017
  01   01001001001                01         1
  02   02002002002       02000000000         1
  04   04004004004          04000000         1
 010  010010010010            010000         1
 020  020020020020               020         1
 040  040040040040      040000000000         1  # 040000000000 == 2 ** 32
0100 0100100100100        0100000000         1
0200 0200200200200           0200000         1

あなたは64ビット演算が使用できない場合、あなたが9つの操作を取って、ニブルにアップc分割し、各半分を行うことができます。これが唯一のように16ビットまたは32ビット演算が動作する使用し、13ビットを必要とする。

bits = ((c & 017) * 0421 & 0111) % 7 + ((c >> 4) * 0421 & 0111) % 7;

(c * 0421 & 01111) % 7
 1   0421      01    1
 2  01042   01000    1
 4  02104    0100    1
 8  04210     010    1

例えば、c == 105 == 0b11001001

c == 0100
   |  040
   |  010
   |   01 == 0151
* 01001001001001ULL == 0100100100100
                     |  040040040040
                     |  010010010010
                     |   01001001001 == 0151151151151
& 0421042104210421ULL ==  0100000000
                       | 04000000000
                       |      010000
                       |          01 ==   04100010001
% 017                                == 4

c & 017      ==            8 | 1           ==                   011
011 * 0421   ==     8 * 0421 | 1 * 0421    == 04210 | 0421 == 04631
04631 & 0111 == 04210 & 0111 | 0421 & 0111 ==   010 | 01   ==   011
011 % 7      == 2

c >> 4       ==            4 | 2            ==                     06
06 * 0421    ==     4 * 0421 | 2 * 0421     == 02104 | 01042 == 03146
03146 & 0111 == 02104 & 0111 | 01042 & 0111 ==  0100 | 01000 == 01100
01100 % 7    == 2

2 + 2 == 4
http://graphics.stanford.edu:

ビットいじるハックページを参照してください。 /~seander/bithacks.html#CountBitsSetKernighanする

このため、多くの優れたソリューションがあります。

また、最も単純な実装では、この機能はかなり簡単です。あなたはこれを行う方法を学ぶために時間を取る必要があります。

あなたは小さなルックアップテーブルを使用して最高のパフォーマンスを得るunsigned char型と小さい整数の場合ます。

私はあなたが言及しているものの人口数のアルゴリズムを知っています。彼らは、レジスタに格納された整数よりも小さい複数の単語の演算を行うことによって動作します。

この技術はSWAR( http://en.wikipedia.org/wiki/SWAR)。

www.hackersdelight.org:

詳細については、私はあなたがハッカーがWebサイトを喜ばチェックアウトをお勧めします。彼は、サンプルコードを持っており、詳細にこれらのトリックを説明する本を書かれています。

すでに答えとして

、カウントビットの標準的な方法はまた、符号なし文字に取り組みます。

例:

    unsigned char value = 91;
int bitCount = 0;
while(value > 0)
{
    if ( value & 1 == 1 ) 
        bitCount++;
    value >>= 1;
}

unsigned char型は、32ビットの浮動小数点又は整数コンパイラが表現するためにそれらを認めるもの「数」であることをちょうど同じように、「番号」で変化するものです。

あなたはそのビットとして文字を描く場合:

01010011(8ビット);

は、次の操作を実行して、設定されたビットをカウントすることができます:

Xを言い、そしてx%2を取ることができ、残りは1または0のいずれかであろうチャーのエンディアン、左または右のほとんどのビットに応じて、すなわち、値をとります。 (これは、セットビットの結果の数である)別の変数に残りを蓄積する。

次に>>(右シフト)1ビット。

8ビットがシフトされるまで、

繰り返します。

Cのコードは私の擬似コードから実装するのに非常に簡単にする必要がありますが、基本的には、

public static int CountSetBits(char c)
{
    int x = 0;
    int setBits = 0;
    while (x < 7)
    {
       setBits = setBits + c % 2;
       c = c >> 1;
       x = x + 1;
    }
}

Ephemientのポスト上のベース、当社は一切分岐鎖の8ビットバージョンを持っていません。これは、16進数表現である。

typedef unsigned char       UINT8;
typedef unsigned short      UINT16;
typedef unsigned long long  UINT64;
int hammingWeight8( const UINT8& c)
{
    return ( c* 0x8040201ULL & 0x11111111)%0xF;
}

私たちは9つの操作を必要とする16ビットバージョンを、持っている、それを2回適用します。

int hammingWeight16( const UINT16& c)
{
    return ((c & 0xFF)* 0x8040201ULL & 0x11111111)%0xF + 
             ((c >> 8)* 0x8040201ULL & 0x11111111)%0xF;
}

ここで私は、64-ビットのレジスタと11回の操作を必要とする変異型16ビットバージョンを記述します。これは、以前のものよりも優れていないようだが、それだけで1つのモジュロ演算を使用します。

int hammingWeight16( const UINT16& c)
{
    UINT64  w;
    w= (((( c* 0x8000400020001ULL)>> 3) & 0x1111111111111111)+14)%0xF;
    return (c!=0)*(w+1+(c==0xFFFF)*15);
}
scroll top