[ビット演算] - 先頭の0の数を計算します。

記事ディレクトリ

効果

x のバイナリ内の先行ゼロの数を返します。
clz(count先行ゼロ) は先行ゼロをカウントします。

「先行ゼロ」とは、数値の先頭、ゼロ以外の数字の前に現れるゼロです。2 進数のコンテキストでは、先行ゼロは、2 進数の先頭、最初の非ゼロ ビットの前にあるビット (0 または 1) を指します。たとえば、00001101最初の非ゼロ ビット (1) の前に 4 つの 2 進ビット (0) があるため、2 進数の先頭には 4 つのゼロがあります。

    int __builtin_clz (unsigned int x)
    Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.

    int __builtin_clzl (unsigned long x)
    Similar to __builtin_clz, except the argument type is unsigned long.

    int __builtin_clzll (unsigned long long x)
    Similar to __builtin_clz, except the argument type is unsigned long long.

GCC の __builtin_clz 関数は、コンパイラの内部最適化を通じて実装されます。正確な実装は、使用するコンパイラのバージョンとターゲット プロセッサ アーキテクチャによって異なります。

最新のプロセッサには、通常、先頭のゼロの数をカウントするための専用の命令があります。GCC はこれらのプロセッサ命令を使用して __builtin_clz 関数を実装し、計算効率を向上させます。

専用の命令を持たないプロセッサの場合、GCC は他のアルゴリズムを使用して先行ゼロの数を計算する場合があります。一般的なアルゴリズムは二分探索法を使用するもので、最上位ビットが 1 である位置が見つかるまで整数を半分に分割し続けます。このアルゴリズムの時間計算量は O(log n) です。ここで、n は整数のビット数です。

__builtin_clz 関数の動作は、コンパイラやプロセッサ アーキテクチャによって異なる場合があることに注意してください。

RISC-Vで実装

RISC-V 命令セットの clz 命令は、符号なし整数の 2 進表現における最上位ビット (MSB) から始まる連続するゼロの数、つまり先頭のゼロの数をカウントするために使用されます。
clz コマンドの構文は次のとおりです。

clz rd, rs1

このうち、rd は計算結果を格納するターゲット レジスタ、rs1 は計算対象の符号なし整数を格納するソース レジスタです。

clz 命令の動作は次のとおりです。

  1. ソースレジスタ rs1 の値を符号なし整数として扱います。
  2. rs1 の最上位ビット (MSB) から開始して、下位ビットまで移動し、最初の非ゼロ ビットに到達するか、値全体が探索されるまで、連続するゼロの数を数えます。
  3. カウントされた先頭のゼロの数を宛先レジスタ rd に保存します。
    以下は、clz 命令を使用して符号なし整数 x の先頭のゼロの数をカウントし、結果をレジスタ a0 に格納する方法を示す例です。
clz a0, x

clz 命令は、RISC-V 命令セットの標準拡張ではオプションであり、サポートされるかどうかは、使用されるプロセッサの実装と命令セット拡張によって決まることに注意してください。したがって、プログラムを作成するときは、関連する RISC-V アーキテクチャとプロセッサのドキュメントを参照して、使用する命令セットが clz 命令をサポートしていることを確認することをお勧めします。

インラインアセンブリの実装

unsigned int __builtin_clz(unsigned int x) {
    
    
    unsigned int count;
    asm ("clz %0, %1" : "=r" (count) : "r" (x));
    return count;
}

ARM上で実装

clz Rd, Rm

clz 命令の動作は次のとおりです。

  1. ソースレジスタ Rm の値を符号なし整数として扱います。
  2. Rm の最上位ビット (MSB) から開始して、下位ビットに移動し、最初の非ゼロ ビットに到達するか、値全体が探索されるまで、連続するゼロの数を数えます。
  3. カウントされた先頭のゼロの数をデスティネーション レジスタ Rd に格納します。

インラインアセンブリの実装

unsigned int __builtin_clz(unsigned int x) {
    
    
    unsigned int count;
    asm ("clz %0, %1" : "=r" (count) : "r" (x));
    return count;
}

使用例

#include <stdio.h>
int main()
{
    
    
    unsigned int x = 0b00000000000000000000000000001100; /* 12 in binary */
    unsigned int leadingZeros = __builtin_clz(x);
    printf("Number of leading zeros: %u\n", leadingZeros);
    return 0;
}

結果は

Number of leading zeros: 28

バイナリ表現の先頭に 28 個のゼロがあることを示します

おすすめ

転載: blog.csdn.net/tyustli/article/details/131957607