programing

C int 어레이를 0으로 리셋: 가장 빠른 방법?

copysource 2022. 8. 27. 23:35
반응형

C int 어레이를 0으로 리셋: 가장 빠른 방법?

T myarray[100]T = int, unsigned int, long long int unsigned long long int int igned으으 으으 、 0 으으으 으으 、 t으으 t t t t t t t t t t t t t t t t 、 t t t t t t t t t t t t t t = int?시메 ??

입니다.T *myarray = new T[100].

memset:<string.h>, 써, 에, 는 조립 시에 직접 작성되고 수작업으로 최적화되는 루틴이기 때문에 아마도 가장 빠른 표준 방법일 것입니다.

memset(myarray, 0, sizeof(myarray)); // for automatically-allocated arrays
memset(myarray, 0, N*sizeof(*myarray)); // for heap-allocated arrays, where N is the number of elements

에서는 'C++'를 사용하는 예요.std::fill:<algorithm>

std::fill(myarray, myarray+N, 0);

자동으로 최적화됩니다.memset는 그것이 > > > > > > > > > > > > 。memset★★★★★★에int될 수 .★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

이 질문은 다소 오래되었지만, 가장 관용적인 방법이나 가장 적은 수의 행으로 가장 빨리 쓸 수 있는 방법을 요구하기 때문에 벤치마크가 필요합니다.그리고 실제 테스트 없이 그 질문에 대답하는 것은 어리석은 일이다.그래서 AnT의 답변의 memset vs. std::fill vs. ZERO vs. AVX 내장 함수를 사용하여 작성한 솔루션을 비교했습니다.

이 솔루션은 일반적이지 않습니다. 32비트 또는 64비트 데이터에서만 작동합니다.이 코드가 올바르지 않으면 코멘트를 주세요.

#include<immintrin.h>
#define intrin_ZERO(a,n){\
size_t x = 0;\
const size_t inc = 32 / sizeof(*(a));/*size of 256 bit register over size of variable*/\
for (;x < n-inc;x+=inc)\
    _mm256_storeu_ps((float *)((a)+x),_mm256_setzero_ps());\
if(4 == sizeof(*(a))){\
    switch(n-x){\
    case 3:\
        (a)[x] = 0;x++;\
    case 2:\
        _mm_storeu_ps((float *)((a)+x),_mm_setzero_ps());break;\
    case 1:\
        (a)[x] = 0;\
        break;\
    case 0:\
        break;\
    };\
}\
else if(8 == sizeof(*(a))){\
switch(n-x){\
    case 7:\
        (a)[x] = 0;x++;\
    case 6:\
        (a)[x] = 0;x++;\
    case 5:\
        (a)[x] = 0;x++;\
    case 4:\
        _mm_storeu_ps((float *)((a)+x),_mm_setzero_ps());break;\
    case 3:\
        (a)[x] = 0;x++;\
    case 2:\
        ((long long *)(a))[x] = 0;break;\
    case 1:\
        (a)[x] = 0;\
        break;\
    case 0:\
        break;\
};\
}\
}

저는 낮은 수준의 최적화 전문가가 아니기 때문에 이것이 가장 빠른 방법이라고 주장하지 않겠습니다.이는 memset보다 빠른 올바른 아키텍처 의존 구현의 예입니다.

자, 이제 결과를 말씀드리겠습니다.100 int 사이즈와 롱 어레이의 퍼포먼스를 정적으로, 동적으로 할당했습니다만, 스태틱 어레이로 데드 코드를 없앤 msvc를 제외하고, 결과는 지극히 비슷했기 때문에 다이내믹 어레이의 퍼포먼스만을 나타냅니다.타임 마킹은 시간을 사용하여 100만 회 반복에 대해 ms입니다.h의 저정밀 클럭 기능.

clang 3.8(clang-cl 프런트 엔드, optimization flags= /OX /arch 사용:AVX/Oi/Ot)

int:
memset:      99
fill:        97
ZERO:        98
intrin_ZERO: 90

long long:
memset:      285
fill:        286
ZERO:        285
intrin_ZERO: 188

gcc 5.1.0(최적화 플래그: -O3 -march=syslog -mtune=syslog -mavx):

int:
memset:      268
fill:        268
ZERO:        268
intrin_ZERO: 91
long long:
memset:      402
fill:        399
ZERO:        400
intrin_ZERO: 185

msvc 2015(최적화 플래그: /OX/arch:AVX/Oi/Ot):

int
memset:      196
fill:        613
ZERO:        221
intrin_ZERO: 95
long long:
memset:      273
fill:        559
ZERO:        376
intrin_ZERO: 188

여기에는 많은 흥미로운 작업이 있습니다.llvm killing gcc는 MSVC의 전형적인 스팟 최적화입니다(정적 어레이에서는 데드 코드를 대폭 배제하고, 그 후 처리 성능이 저하됩니다).구현이 상당히 빠르지만 이는 비트 클리어에 의한 오버헤드가 다른 설정 조작보다 훨씬 적다는 것을 인식하기 때문일 수 있습니다.

Clang의 구현은 훨씬 더 빠르기 때문에 더 검토할 가치가 있습니다.일부 추가 테스트에 따르면 이 memset은 사실상 제로 전용입니다.400바이트 어레이의 non-zero memset은 훨씬 느리고(~220ms), gcc와 비슷합니다.단, 800바이트 어레이를 사용한0 이외의 메모리 설정은 속도 차이는 없습니다.그 때문에, 그 memset의 퍼포먼스가 실장보다 나빠질 가능성이 있습니다.특화 대상은 소규모 어레이뿐이며, 컷토프는 800바이트 정도입니다.또한 gcc 'fill'과 'ZERO'는 memset에 최적화되어 있지 않으며(생성된 코드를 참조), gcc는 단순히 동일한 성능 특성을 가진 코드를 생성합니다.

결론: memset은 실제로 이 작업에 최적화되어 있지 않습니다(그렇지 않으면 gcc와 msvc, llvm의 memset은 동일한 성능을 가집니다).퍼포먼스가 중요한 경우, 특히 이러한 어색한 중간 크기 어레이의 경우, memset은 최종 솔루션이 되지 않아야 합니다.memset은 비트 클리어에 특화되어 있지 않고 컴파일러 자체보다 수작업으로 최적화되어 있지 않기 때문입니다.

송신원:

memset(myarray, 0, sizeof(myarray));

사용할 수 있습니다.sizeof(myarray)의 크기라면myarray는 컴파일 시에 알 수 있습니다.그렇지 않은 경우, 예를 들어 를 통해 얻은 동적 크기 어레이를 사용하는 경우malloc또는new, 길이를 기록해 둘 필요가 있습니다.

사용할 수 있습니다.memset다만, 타입의 선택이 일체형으로 한정되어 있기 때문입니다.

일반적으로 C에서는 매크로를 구현하는 것이 타당합니다.

#define ZERO_ANY(T, a, n) do{\
   T *a_ = (a);\
   size_t n_ = (n);\
   for (; n_ > 0; --n_, ++a_)\
     *a_ = (T) { 0 };\
} while (0)

이를 통해 C++와 같은 기능을 통해 다음과 같은 해킹에 의존하지 않고 모든 유형의 오브젝트 배열을 "0으로 리셋"할 수 있습니다.memset기본적으로 이것은 C++ 함수 템플릿의 C 아날로그입니다.단, type 인수를 명시적으로 지정해야 합니다.

또한 노후되지 않은 어레이를 위한 "템플릿"을 구축할 수 있습니다.

#define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
#define ZERO_ANY_A(T, a) ZERO_ANY(T, (a), ARRAY_SIZE(a))

이 예에서는 다음과 같이 적용됩니다.

int a[100];

ZERO_ANY(int, a, 100);
// or
ZERO_ANY_A(int, a);

특히 스칼라 타입의 오브젝트에 대해서는 타입에 의존하지 않는 매크로를 실장할 수 있는 것도 주의할 필요가 있습니다.

#define ZERO(a, n) do{\
   size_t i_ = 0, n_ = (n);\
   for (; i_ < n_; ++i_)\
     (a)[i_] = 0;\
} while (0)

그리고.

#define ZERO_A(a) ZERO((a), ARRAY_SIZE(a))

위의 예를 로 변환

 int a[100];

 ZERO(a, 100);
 // or
 ZERO_A(a);

정적 선언의 경우 다음을 사용할 수 있습니다.

T myarray[100] = {0};

도 같은 합니다. 즉, '동적 선언'입니다.memset

zero(myarray);C++로 하다

머리글에 추가하기만 하면 됩니다.

template<typename T, size_t SIZE> inline void zero(T(&arr)[SIZE]){
    memset(arr, 0, SIZE*sizeof(T));
}

사용하는 기능은 다음과 같습니다.

template<typename T>
static void setValue(T arr[], size_t length, const T& val)
{
    std::fill(arr, arr + length, val);
}

template<typename T, size_t N>
static void setValue(T (&arr)[N], const T& val)
{
    std::fill(arr, arr + N, val);
}

다음과 같이 말할 수 있습니다.

//fixed arrays
int a[10];
setValue(a, 0);

//dynamic arrays
int *d = new int[length];
setValue(d, length, 0);

위의 방법은 memset을 사용하는 방법보다 C++11 방법이 더 많습니다.크기를 지정하여 동적 배열을 사용하는 경우에도 컴파일 시간 오류가 발생합니다.

언급URL : https://stackoverflow.com/questions/9146395/reset-c-int-array-to-zero-the-fastest-way

반응형