7


1

intの配列を効率的にビットシフトしますか?

同じページに配置するために、sizeof(int)= 4およびsizeof(long)= 8と仮定します。

整数の配列が与えられた場合、配列を左または右に論理的にビットシフトする効率的な方法は何でしょうか?

要素の最初のペア(インデックス0と1)のビットシフトを計算し、最初の要素(0)を設定するlongなどの補助変数を考えています。 このように続けると、要素(インデックス1および2)のビットシフトはコンピューターになり、インデックス1が設定されます。

これは実際にはかなり効率的な方法だと思いますが、欠点もあります。 32ビットを超えるビットシフトはできません。 複数の補助変数を使用するとうまくいくと思いますが、線に沿ったどこかで再帰を想定しています。

3 Answer


8


中継として「long」を使用する必要はありません。 左にシフトする場合は、最高位の整数から開始し、右にシフトする場合は最低から開始します。 変更する前に、隣接する要素からキャリーを追加します。

void ShiftLeftByOne(int * arr, int len)
{
    int i;
    for (i = 0;  i < len - 1;  ++i)
    {
        arr[i] = (arr[i] << 1) | ((arr[i+1] >> 31) & 1);
    }
    arr[len-1] = arr[len-1] << 1;
}

この手法は、1ビット以上のシフトを行うように拡張できます。 32ビット以上を実行している場合、ビットカウントmod 32を取得し、それだけシフトし、結果を配列内でさらに移動します。 たとえば、左に33ビットシフトすると、コードはほぼ同じになります。

void ShiftLeftBy33(int * arr, int len)
{
    int i;
    for (i = 0;  i < len - 2;  ++i)
    {
        arr[i] = (arr[i+1] << 1) | ((arr[i+2] >> 31) & 1);
    }
    arr[len-2] = arr[len-1] << 1;
    arr[len-1] = 0;
}


1


JavaでのBigIntegerの実装をご覧ください。これは、データをバイトの配列として内部に保存します。 具体的には、関数leftShift()をチェックアウトできます。 構文はCの場合と同じなので、これらのような機能のペアを記述することはそれほど難しくありません。 また、ビットシフトに関しては、Cで未定義の型の利点を活用できることを考慮してください。 これは、Javaで符号をいじらずに安全にデータをシフトするには、通常、データを保持するためにより大きな型が必要であることを意味します(つまり、 ショートをシフトするint、intをシフトするlong、…​)


1


他の人にとっては、これは任意のビット数と任意のタイプの配列に関する上記のhttps://stackoverflow.com/a/2774161/1698972[Mark Ransom’s answer]の*より一般的なバージョンです:

/* This function shifts an array of byte of size len by shft number of
bits to the left. Assumes array is big endian. */

#define ARR_TYPE uint8_t

void ShiftLeft(ARR_TYPE * arr_out, ARR_TYPE * arr_in, int arr_len, int shft)
{
    const int int_n_bits = sizeof(ARR_TYPE) * 8;
    int msb_shifts = shft % int_n_bits;
    int lsb_shifts = int_n_bits - msb_shifts;
    int byte_shft = shft / int_n_bits;
    int last_byt = arr_len - byte_shft - 1;
    for (int i = 0;  i < arr_len;  i++){
        if (i <= last_byt){
            int msb_idx = i + byte_shft;
            arr_out[i] = arr_in[msb_idx] << msb_shifts;
            if (i != last_byt)
                arr_out[i] |= arr_in[msb_idx + 1] >> lsb_shifts;
        }
        else arr_out[i] = 0;
    }
}