-1

2 バイト配列のXOR 演算を効率的に行う方法を検討しています。このバイト配列を定義したのは、それらをXORする方がはるかに高速になると 思うからです。本当ですか?できればXORingループ内でこれにどのくらい効率的に変換しますか? バイト配列%8の長さが 0 でない場合、最後のバイトをパディングする方法は?unsigned char *uint64_tunsigned char *uint64_t *

バイト配列を XOR する現在のコードを次に示しますが、各バイト (符号なし char) は個別に:

unsigned char *bitwise_xor(const unsigned char *A_Bytes_Array, const unsigned char *B_Bytes_Array, const size_t length) {

    unsigned char *XOR_Bytes_Array;

    // allocate XORed bytes array
    XOR_Bytes_Array = malloc(sizeof(unsigned char) * length);

    // perform bitwise XOR operation on bytes arrays A and B
    for(int i=0; i < length; i++)
        XOR_Bytes_Array[i] = (unsigned char)(A_Bytes_Array[i] ^ B_Bytes_Array[i]);

    return XOR_Bytes_Array;
}

わかりました、その間、私はこのようにしようとしました。私のbytes_arrayはかなり大きいです(rgbaビットマップ4 * 1440 * 900?)。

static uint64_t next64bitsFromBytesArray(const unsigned char *bytesArray, const int i) {

    uint64_t next64bits = (uint64_t) bytesArray[i+7] | ((uint64_t) bytesArray[i+6] << 8) | ((uint64_t) bytesArray[i+5] << 16) | ((uint64_t) bytesArray[i+4] << 24) | ((uint64_t) bytesArray[i+3] << 32) | ((uint64_t) bytesArray[i+2] << 40) | ((uint64_t) bytesArray[i+1] << 48) | ((uint64_t)bytesArray[i] << 56);
    return next64bits;
}

unsigned char *bitwise_xor64(const unsigned char *A_Bytes_Array, const unsigned char *B_Bytes_Array, const size_t length) {

    unsigned char *XOR_Bytes_Array;

    // allocate XORed bytes array
    XOR_Bytes_Array = malloc(sizeof(unsigned char) * length);

    // perform bitwise XOR operation on bytes arrays A and B using uint64_t
    for(int i=0; i<length; i+=8) {

        uint64_t A_Bytes = next64bitsFromBytesArray(A_Bytes_Array, i);
        uint64_t B_Bytes = next64bitsFromBytesArray(B_Bytes_Array, i);
        uint64_t XOR_Bytes = A_Bytes ^ B_Bytes;
        memcpy(XOR_Bytes_Array + i, &XOR_Bytes, 8);
    }

    return XOR_Bytes_Array; 
} 

更新: (この問題への 2 番目のアプローチ)

unsigned char *bitwise_xor64(const unsigned char *A_Bytes_Array, const unsigned char *B_Bytes_Array, const size_t length) {

    const uint64_t *aBytes = (const uint64_t *) A_Bytes_Array;
    const uint64_t *bBytes = (const uint64_t *) B_Bytes_Array;

    unsigned char *xorBytes = malloc(sizeof(unsigned char)*length);

    for(int i = 0, j=0; i < length; i +=8) {
            uint64_t aXORbBytes = aBytes[j] ^ bBytes[j];
            //printf("a XOR b = 0x%" PRIx64 "\n", aXORbBytes);
            memcpy(xorBytes + i, &aXORbBytes, 8);
            j++;
    }

    return xorBytes;
}
4

1 に答える 1

0

だから私は実験をしました:

#include <stdlib.h>
#include <stdint.h>

#ifndef TYPE
#define TYPE uint64_t
#endif

TYPE *
xor(const void *va, const void *vb, size_t l)
{
        const TYPE *a = va;
        const TYPE *b = vb;
        TYPE *r = malloc(l);
        size_t i;

        for (i = 0; i < l / sizeof(TYPE); i++) {
                *r++ = *a++ ^ *b++;
        }
        return r;
}

基本的な最適化を使用して、clang用uint64_tおよびclangの両方でコンパイルされています。uint8_tどちらの場合も、コンパイラはこれを完全にベクトル化しました。違いは、uint8_t バージョンにlは 8 の倍数でない場合に処理するコードがあったことです。そのため、サイズが 8 の倍数でない場合に処理するコードを追加すると、おそらく同等のコードが生成されることになります。また、64 ビット バージョンではループが数回アンロールされ、それを処理するコードが含まれていたため、配列が十分に大きい場合は、ここで数パーセントを得ることができます。一方、十分に大きな配列では、メモリが制限され、xor 操作はほとんど問題になりません。

コンパイラがこれを処理しないと確信していますか? これは一種のマイクロ最適化であり、物事を測定している場合にのみ意味があり、どちらが速いかを尋ねる必要はありません。

于 2016-10-18T10:57:21.187 に答える