文字列の ハミング重みは、使用されているアルファベットのゼロ記号と異なる記号の数です。したがって、これは同じ長さのすべてゼロの文字列からのハミング距離に相当します。最も一般的なケースであるビットの文字列の場合、これは文字列内の 1 の数、または指定された数のバイナリ表現とビットベクトルのℓ ₁ ノルムの桁合計です。このバイナリの場合、これは人口カウント、[1]、ポップカウント、横方向合計、[2]、またはビット合計とも呼ばれます。[3]

歴史と使用法
ハミング重みはアメリカの数学者リチャード・ハミングにちなんで名付けられましたが、この概念を最初に考案したのはハミングではありません。[5] 2進数のハミング重みは、1899年にジェームズ・WL・グレイシャーによってパスカルの三角形の1行に含まれる奇数の2項係数の数を表す式を与えるためにすでに使用されていました。[6]アーヴィング・S・リードは、 2進数の場合のハミング重みに相当する概念を1954年に導入しました。[7]
ハミング重みは、情報理論、符号理論、暗号化など、さまざまな分野で使用されています。ハミング重みの応用例には、次のようなものがあります。
- を二乗するモジュラー指数法では、指数eに必要なモジュラー乗算の回数はlog 2 e + weight( e )である。これが、 RSAで使用される公開鍵の値eが通常、ハミング重みが低い数に選択される理由である。 [8]
- ハミング重みは、Chord分散ハッシュテーブル内のノード間のパスの長さを決定します。[9]
- 生体認証データベースでのIrisCode検索は、通常、保存されている各レコードへのハミング距離を計算することによって実装されます。
- ビットボード表現を使用するコンピュータ チェスプログラムでは、ビットボードのハミング重みは、ゲームに残っている特定の種類の駒の数、または 1 人のプレーヤーの駒によって制御されるボードのマス目数を示すため、位置の値に重要な影響を与える用語です。
- ハミング重みは、 ffs(x) = pop(x ^ (x - 1))という恒等式を使用して、find first setを効率的に計算するために使用できます。これは、ハードウェアハミング重み命令はあるが、ハードウェアfind first set命令がないSPARCなどのプラットフォームで役立ちます。 [10] [1]
- ハミング重み演算は、一進数から二進数への変換として解釈できる。[11]
- ビットベクトルやウェーブレットツリーなどの簡潔なデータ構造の実装。
効率的な実装
暗号やその他のアプリケーションでは、ビット列の人口カウントが必要になることがよくあります。2つの単語AとBのハミング距離は、 A xor Bのハミング重みとして計算できます。[1]
これを効率的に実装する方法の問題は、広く研究されてきました。一部のプロセッサでは、計算のための単一の操作、またはビット ベクトルの並列操作が可能です。これらの機能を備えていないプロセッサの場合、ツリー パターンでカウントを追加することが、最も優れたソリューションとして知られています。たとえば、16 ビットの 2 進数 a = 0110 1100 1011 1010 の 1 ビットの数をカウントするには、次の操作を実行します。
ここでの演算はCプログラミング言語と同様で、X >> YXをYビット右にシフトすることを意味し、X & YはXとYのビットANDを意味し、+は通常の加算を意味します。この問題に対する最も優れたアルゴリズムは、上記の概念に基づいており、ここに示されています。[1]
//以下の関数で使用される型と定数
//uint64_t は符号なし 64 ビット整数変数型です (C 言語の C99 バージョンで定義されています)
const uint64_t m1 = 0x5555555555555555 ; // バイナリ: 0101... const uint64_t m2 = 0x333333333333333 ; // バイナリ: 00110011... const uint64_t m4 = 0x0f0f0f0f0f0f0f0f ; // バイナリ: 4 つのゼロ、4 つの 1... const uint64_t m8 = 0x00ff00ff00ff00ff ; // バイナリ: 0 が 8 個、1 が 8 個... const uint64_t m16 = 0x0000ffff0000ffff ; // バイナリ: 0 が 16 個、1 が 16 個... const uint64_t m32 = 0x00000000ffffffff ; // バイナリ: 0 が 32 個、1 が 32 個const uint64_t h01 = 0x0101010101010101 ; // 256 の 0、1、2、3 乗の合計...
// これは単純な実装で、比較のため、
またより優れた機能の理解を助けるために示されています。
// このアルゴリズムは 24 の算術演算 (シフト、加算、および) を使用します。
int popcount64a ( uint64_t x ) { x = ( x & m1 ) + (( x >> 1 ) & m1 ); // 各 2 ビットのカウントをこれらの 2 ビットに格納しますx = ( x & m2 ) + ( ( x >> 2 ) & m2 ); // 各 4 ビットのカウントをこれらの 4 ビットに格納しますx = ( x & m4 ) + (( x >> 4 ) & m4 ); // 各 8 ビットのカウントをこれらの 8 ビットに格納しますx = ( x & m8 ) + (( x >> 8 ) & m8 ); // 各 16 ビットのカウントをこれらの 16 ビットに格納しますx = ( x & m16 ) + (( x >> 16 ) & m16 ); // 各 32 ビットのカウントをその 32 ビットに格納しますx = ( x & m32 ) + (( x >> 32 ) & m32 ); // 各 64 ビットのカウントをその 64 ビットに格納しますreturn x ; }
//これは、遅い乗算を行うマシン上の
他の既知の実装よりも少ない算術演算を使用します 。 //このアルゴリズムは17の算術演算を使用します。
int popcount64b ( uint64_t x ) { x -= ( x >> 1 ) & m1 ; //各2ビットのカウントをそれらの2ビットに格納しますx = ( x & m2 ) + (( x >> 2 ) & m2 ); //各4ビットのカウントをそれらの4ビットに格納しますx = ( x + ( x >> 4 )) & m4 ; //各8ビットのカウントをそれらの8ビットに格納しますx += x >> 8 ; //各16ビットのカウントをそれぞれの最下位8ビットに格納しますx += x >> 16 ; //各32ビットのカウントをそれぞれの最下位8ビットに格納しますx += x >> 32 ; //各64ビットのカウントをそれぞれの最下位8ビットに格納しますreturn x & 0x7f ; }
//これは、高速乗算機能を備えたマシン上の他の既知の
実装よりも少ない算術演算を使用します。
//このアルゴリズムは12の算術演算を使用し、そのうちの1つは乗算です。
int popcount64c ( uint64_t x ) { x -= ( x >> 1 ) & m1 ; //各2ビットのカウントをこれらの2ビットに格納しますx = ( x & m2 ) + (( x >> 2 ) & m2 ); //各4ビットのカウントをこれらの4ビットに格納しますx = ( x + ( x >> 4 )) & m4 ; //各8ビットのカウントをこれらの8ビットに格納しますreturn ( x * h01 ) >> 56 ; //xの左8ビットを返します + (x<<8) + (x<<16) + (x<<24) + ... }
上記の実装は、既知のアルゴリズムの中で最も悪いケースでの動作が優れています。ただし、値に非ゼロビットがほとんどないと予想される場合は、これらのビットを 1 つずつカウントするアルゴリズムを使用する方が効率的です。Wegner が 1960 年に説明したように、[12] xとx − 1 のビット単位のAND は、最下位の非ゼロビットをゼロにする点のみがx と異なります。つまり、1 を引くと、右端の 0 の文字列が 1 に変わり、右端の 1 が 0 に変わります。xに元々 1 であるビットがn個あった場合、この操作をn 回繰り返すだけで、 x はゼロになります。次の実装はこの原理に基づいています。
// x のほとんどのビットが 0 の場合、この方法の方が適しています
// このアルゴリズムは、すべてのデータ サイズで同じように動作します。
// このアルゴリズムは、x の "1" ビットごとに 3 つの算術演算と 1 つの比較/分岐を使用します。
int popcount64d ( uint64_t x ) { int count ; for ( count = 0 ; x ; count ++ ) x &= x - 1 ; return count ; }
より多くのメモリ使用量が許容される場合、上記の方法よりも速くハミング重みを計算できます。メモリが無制限であれば、64 ビット整数ごとのハミング重みの大きなルックアップ テーブルを簡単に作成できます。16 ビット整数ごとのハミング関数のルックアップ テーブルを保存できる場合は、次の操作を実行して 32 ビット整数ごとのハミング重みを計算できます。
static uint8_t wordbits [ 65536 ] = { /* 0 から 65535 までの整数のビットカウント */ }; //このアルゴリズムは 3 つの算術演算と 2 つのメモリ読み取りを使用します。int popcount32e ( uint32_t x ) { return wordbits [ x & 0xFFFF ] + wordbits [ x >> 16 ]; }
//オプションで、wordbits[]テーブルはこの関数を使用して埋めることができます
int popcount32e_init ( void ) { uint32_t i ; uint16_t x ; int count ; for ( i = 0 ; i <= 0xFFFF ; i ++ ) { x = i ; for ( count = 0 ; x ; count ++ ) //上記のpopcount64d()から借用x &= x - 1 ; wordbits [ i ] = count ; } }
Mułaら[13]は、 popcount64bのベクトル化されたバージョンが専用命令(例えば、x64プロセッサ上のpopcnt)よりも高速に実行できることを示しました。
最小重量
誤り訂正符号化では、最小ハミング重み(一般にコードの最小重み w minと呼ばれる)は、重みが最も小さい非ゼロのコード ワードの重みです。コード ワードの重みwは、ワード内の 1 の数です。たとえば、ワード 11001010 の重みは 4 です。
線形ブロック符号では、最小重みは最小ハミング距離(d min)でもあり、符号の誤り訂正能力を定義します。w min = n の場合、 d min = n となり、符号 は 最大d min /2個の誤りを訂正します。[14]
言語サポート
一部のCコンパイラはビットカウント機能を提供する組み込み関数を提供しています。たとえば、GCC(2004年4月のバージョン3.4以降)には、__builtin_popcount利用可能な場合はプロセッサ命令を使用し、そうでない場合は効率的なライブラリ実装を使用する組み込み関数が含まれています。[15] LLVM-GCCは、2005年6月のバージョン1.5以降、この関数を含んでいます。 [16]
C++ 標準ライブラリでは、ビット配列データ構造に、設定されているビットの数をカウントするメソッドがbitsetあります。C ++20では、符号なし整数型の引数を取る関数とを含む新しいヘッダーが追加されました。
count()<bit>std::popcountstd::has_single_bit
Java では、拡張可能なビット配列データ構造に、設定されているビットの数をカウントするメソッドがあります。さらに、BitSetプリミティブ32 ビット整数と 64 ビット整数のビットをそれぞれカウントすると関数があります。また、任意精度整数クラスにもビットをカウントするメソッドがあります。
BitSet.cardinality()Integer.bitCount(int)Long.bitCount(long)BigIntegerBigInteger.bitCount()
Pythonでは、型には設定されているビットの数をカウントするメソッドintがあります。この機能は、2021年10月にリリースされたPython 3.10で導入されました。 [17]bit_count()
Common Lispでは、関数 はlogcount、負でない整数を与えると、 1 のビットの数を返します。(負の整数の場合は、2 の補数表記で 0 のビットの数を返します。) どちらの場合でも、整数は BIGNUM にすることができます。
GHC 7.4以降、 Haskellベースパッケージには、クラスpopCountのインスタンスであるすべての型で使用できる関数が含まれていますBits(モジュールから利用可能Data.Bits)。[18]
MySQLバージョンのSQL言語はBIT_COUNT()標準機能として提供されています。[19]
Fortran 2008にpopcntは、整数(または整数配列)内の非ゼロビットの数を返す標準的な組み込み要素関数があります。 [20]
#B一部のプログラム可能な科学計算用ポケット電卓には、設定されたビットの数を計算するための特別なコマンドが搭載されている。例えば、HP-16C [3] [21]やWP 43S、[22] [23] #BITS[24] [25]またはBITSUM[26] [27]のHP-16Cエミュレータ、およびWP 34S [28] [29]nBITSなどである。
FreePascalはバージョン3.0以降でpopcntを実装している。[30]
プロセッササポート
- 1960年代のIBM STRETCHコンピュータは、すべての論理演算の副産物として、設定されたビットの数と先頭のゼロの数を計算しました。 [1]
- クレイ社のスーパーコンピュータは初期には人口カウントマシン命令を搭載していたが、これは米国政府の国家安全保障局が暗号解読アプリケーションのために特別に要求したものと噂されている。 [1]
- Control Data Corporation (CDC) の6000およびCyber 70/170シリーズ マシンには、人口カウント命令が含まれていました。COMPASS では、この命令は としてコード化されていました
CXi。 - 64ビットSPARCバージョン9アーキテクチャでは
POPC命令が定義されているが[10] [1]、ほとんどの実装ではこれを実装しておらず、オペレーティングシステムでエミュレートする必要がある。[31] - ドナルド・クヌースの著書『The Art of Computer Programming』でMIXに代わるモデル コンピュータMMIX には、1999 年から命令があります。b で 1 で c で 0 であるすべてのビットをカウントし、その結果を a に書き込みます。
SADDSADD a,b,c - 1999 年にリリースされたCompaqのAlpha 21264A は、カウント拡張 (
CIX) を備えた最初の Alpha シリーズ CPU 設計でした。 - アナログ・デバイセズのBlackfin
ONESプロセッサは、32ビットの人口カウントを実行する命令を備えています。 [32] - AMDのBarcelonaアーキテクチャでは、2007 年にSSE4a拡張の一部として命令を導入した高度なビット操作 (ABM) ISAが導入されました。
POPCNT - Intel Coreプロセッサでは、SSE4.2命令セット
POPCNT拡張を備えた命令が導入され、2008 年 11 月にリリースされたNehalemベースのCore i7プロセッサで初めて利用可能になりました。 - ARMアーキテクチャでは、Advanced SIMD ( NEON
VCNT) 拡張の一部としてこの命令が導入されました。 - RISC -V
CPOPアーキテクチャでは、ビット操作(B)拡張の一部としてこの命令が導入されました。 [33]
参照
参考文献
- ^ abcdefg ウォーレン・ジュニア、ヘンリー・S. (2013) [2002]。Hacker 's Delight(第2版)。アディソン・ウェズリー-ピアソン・エデュケーション社。pp . 81–96。ISBN 978-0-321-84268-80-321-84268-5。
- ^ Knuth, Donald Ervin (2009)。「ビットごとのトリックとテクニック;二分決定図」。The Art of Computer Programming。第 4 巻、第 1 巻。Addison–Wesley Professional。ISBN 978-0-321-58050-4。(注: Fascicle 1b の草稿は 2016-03-12 にアーカイブされており、Wayback Machineでダウンロード可能です。)
- ^ ab Hewlett-Packard HP-16C Computer Scientist Owner's Handbook (PDF)。Hewlett -Packard Company。1982年4月。00016-90001。2017年3月28日時点のオリジナルよりアーカイブ(PDF) 。2017年3月28日閲覧。
- ^ R.Ugalde, Laurence. 「Population count the Fōrmulæ programming language」. Fōrmulæ . 2024年6月2日閲覧。
- ^ トンプソン、トーマス M. (1983)。誤り訂正符号から球面パッキングを経て単純群まで。カルス数学モノグラフ #21。アメリカ数学協会。p. 33。
- ^ Glaisher, James Whitbread Lee (1899). 「素数係数に関する二項定理係数の剰余について」.純粋応用数学季刊誌. 30 : 150–156.(注:特に156ページの最後の段落を参照してください。)
- ^ Reed, Irving Stoy (1954)。「多重誤り訂正符号のクラスと復号方式」。IRE情報理論専門家グループ。PGIT-4。無線技術者協会(IRE): 38–49。
- ^ Cohen, Gérard D. ; Lobstein, Antoine; Naccache, David; Zémor, Gilles (1998). 「指数ブラックボックスを改善する方法」。Nyberg, Kaisa (編)。Advances in Cryptology – EUROCRYPT '98、国際暗号技術理論および応用会議、エスポー、フィンランド、1998 年 5 月 31 日~6 月 4 日、議事録。Lecture Notes in Computer Science。Vol. 1403。Springer。pp. 211~220。doi : 10.1007/ BFb0054128。ISBN 978-3-540-64518-4。
- ^ Stoica, I.; Morris, R.; Liben-Nowell, D.; Karger, DR; Kaashoek, MF; Dabek, F.; Balakrishnan, H. (2003 年 2 月)。「Chord: インターネット アプリケーション向けのスケーラブルなピアツーピア検索プロトコル」。IEEE / ACM Transactions on Networking。11 ( 1): 17–32。doi :10.1109/TNET.2002.808407。S2CID 221276912。セクション 6.3:「一般に、追跡する必要が ある
指の数は、ノードからクエリまでの距離の 2 進表現の 1 の数になります。」
- ^ ab SPARC International, Inc. (1992). 「A.41: Population Count. Programming Note」. SPARCアーキテクチャ マニュアル: バージョン 8 (バージョン 8 版)。米国ニュージャージー州エングルウッド クリフス: Prentice Hall。pp. 231。ISBN 0-13-825001-4。
- ^ Blaxell, David (1978)。 Hogben, David; Fife, Dennis W. (編著)。 「ビットパターンマッチングによるレコードリンク」。コンピュータサイエンスと統計 - 第 10 回インターフェイスシンポジウム。 NBS 特別出版。503。米国商務省/国立標準局: 146–156。
- ^ Wegner, Peter (1960 年 5 月). 「バイナリ コンピュータで 1 をカウントする手法」. Communications of the ACM . 3 (5): 322. doi : 10.1145/367236.367286 . S2CID 31683715.
- ^ Muła, Wojciech; Kurz, Nathan; Lemire, Daniel (2018 年 1 月). 「AVX2 命令を使用したより高速な人口カウント」. Computer Journal . 61 (1): 111–120. arXiv : 1611.07612 . doi :10.1093/comjnl/bxx046. S2CID 540973.
- ^ Stern & Mahmoud、「Communications System Design」、Prentice Hall、2004年、477ページ以降。
- ^ 「GCC 3.4 リリースノート」。GNUプロジェクト。
- ^ 「LLVM 1.5 リリースノート」。LLVM プロジェクト。
- ^ 「Python 3.10 の新機能」. python.org .
- ^ 「GHC 7.4.1 リリースノート」。GHC ドキュメント。
- ^ 「第12.11章 ビット関数 — MySQL 5.0 リファレンスマニュアル」
- ^ メトカーフ、マイケル、リード、ジョン、コーエン、マルコム (2011)。Modern Fortran Explained。オックスフォード大学出版局。p. 380。ISBN 978-0-19-960142-4。
- ^ Schwartz, Jake; Grevelle, Rick (2003-10-20) [1993]. HP48S/SX用HP16Cエミュレータライブラリ。1.20 (第1版) 。2015年8月15日閲覧。(注: このライブラリは、 HP 48G / GX / G+でも動作します。HP -16Cの機能セットを超えて、このパッケージは、通常の 10 進浮動小数点数に加えて、科学的記数法による2 進数、8 進数、 16 進数の浮動小数点数の計算もサポートします。)
- ^ Bonin, Walter (2019) [2015]. WP 43S 取扱説明書(PDF) . 0.12 (ドラフト版). p. 135. ISBN 978-1-72950098-9. 2019年8月5日閲覧。[永久リンク切れ ] [1] [2] (314ページ)
- ^ ボニン、ウォルター(2019)[2015]。WP 43Sリファレンスマニュアル(PDF) 。0.12(ドラフト版)。pp. xiii、104、115、120、188。ISBN 978-1-72950106-1. 2019年8月5日閲覧。[永久リンク切れ ] [3] [4] (271ページ)
- ^ Martin, Ángel M.; McClure, Greg J. (2015-09-05). 「HP-41CX 用 HP16C エミュレーター モジュール - ユーザーズ マニュアルと QRG」(PDF)。2017 年 4 月 27 日のオリジナルからアーカイブ(PDF) 。2017 年 4 月 27 日閲覧。(注: HP-16C機能セットを超えて、 HP-41CX用のこのカスタム ライブラリは、約 50 の追加機能によって電卓の機能を拡張します。)
- ^ Martin, Ángel M. (2015-09-07). 「HP-41: 新しい HP-16C エミュレーターが利用可能」。2017-04-27 時点のオリジナルよりアーカイブ。2017-04-27閲覧。
- ^ トーングレン、ホーカン (2017-01-10)。 「Ladybug Documentation」(リリース 0A 版)。2017-01-29に取得。[5]
- ^ 「新しいHP-41モジュールが利用可能:Ladybug」。2017年1月10日。2017年1月29日時点のオリジナルよりアーカイブ。2017年1月29日閲覧。
- ^ Dale, Paul; Bonin, Walter (2012) [2008]. 「WP 34S オーナーズマニュアル」(PDF) (3.1 版) . 2017年4月27日閲覧。
- ^ ボニン、ウォルター (2015) [2008]。WP 34S オーナーズマニュアル(第3.3版)。CreateSpace Independent Publishing Platform。ISBN 978-1-5078-9107-0。
- ^ 「Free Pascal ドキュメント popcnt」。2019年 12 月 7 日閲覧。
- ^ 「JDK-6378821: bitCount() は SPARC プロセッサおよび AMD+10h では POPC を使用する必要があります」。Javaバグ データベース。2006 年 1 月 30 日。
- ^ Blackfin 命令セットリファレンス(暫定版)。アナログデバイス。2001 年。8 ~ 24 ページ。部品番号 82-000410-14。
- ^ Wolf, Claire (2019-03-22). 「RISC-V 用 RISC-V "B" ビット操作拡張、ドラフト v0.37」( PDF)。Github 。
さらに読む
- Schroeppel, Richard C. ; Orman, Hilarie K. (1972-02-29)。「コンパイル」。HAKMEM。Beeler , Michael、Gosper, Ralph William、Schroeppel, Richard C. (レポート) 著。人工知能研究所、マサチューセッツ工科大学、マサチューセッツ州ケンブリッジ、米国。MIT AI メモ 239。(項目 169: PDP/6-10 の人口カウント アセンブリ コード)
外部リンク
- 集計マジック アルゴリズム。最適化された人口カウントとその他のアルゴリズムをサンプル コードで説明します。
- ビット操作ハック ビットをカウントするためのコードが設定されたいくつかのアルゴリズム。
- 必要かつ十分 2017-09-23 にWayback Machineにアーカイブ- Damien Wintour 著 - さまざまなハミング重み実装の C# コードが含まれています。
- 32 ビット整数内のセット ビットの数をカウントする最適なアルゴリズムはどれですか? - Stackoverflow
