컴퓨터에서 궁금한 것을 발견했습니다. * 필기 분할 성 테스트는 %
작업자 보다 훨씬 빠릅니다 . 최소한의 예를 고려하십시오.
* AMD Ryzen Threadripper 2990WX, GCC 9.2.0
static int divisible_ui_p(unsigned int m, unsigned int a)
{
if (m <= a) {
if (m == a) {
return 1;
}
return 0;
}
m += a;
m >>= __builtin_ctz(m);
return divisible_ui_p(m, a);
}
이 예는 홀수 a
및 로 제한됩니다 m > 0
. 그러나, 그것은 쉽게 모든 일반화 될 수 a
와 m
. 이 코드는 나누기를 일련의 추가로 변환합니다.
이제 다음으로 컴파일 된 테스트 프로그램을 고려하십시오 -std=c99 -march=native -O3
.
for (unsigned int a = 1; a < 100000; a += 2) {
for (unsigned int m = 1; m < 100000; m += 1) {
#if 1
volatile int r = divisible_ui_p(m, a);
#else
volatile int r = (m % a == 0);
#endif
}
}
... 내 컴퓨터의 결과 :
| implementation | time [secs] |
|--------------------|-------------|
| divisible_ui_p | 8.52user |
| builtin % operator | 17.61user |
따라서 2 배 이상 빠릅니다.
질문 : 코드가 컴퓨터에서 어떻게 동작하는지 알려줄 수 있습니까? GCC에서 최적화 기회를 놓쳤습니까? 이 시험을 더 빨리 할 수 있습니까?
업데이트 : 요청에 따라 최소한의 재현 가능한 예는 다음과 같습니다.
#include <assert.h>
static int divisible_ui_p(unsigned int m, unsigned int a)
{
if (m <= a) {
if (m == a) {
return 1;
}
return 0;
}
m += a;
m >>= __builtin_ctz(m);
return divisible_ui_p(m, a);
}
int main()
{
for (unsigned int a = 1; a < 100000; a += 2) {
for (unsigned int m = 1; m < 100000; m += 1) {
assert(divisible_ui_p(m, a) == (m % a == 0));
#if 1
volatile int r = divisible_ui_p(m, a);
#else
volatile int r = (m % a == 0);
#endif
}
}
return 0;
}
gcc -std=c99 -march=native -O3 -DNDEBUG
AMD Ryzen Threadripper 2990WX에서 컴파일
gcc --version
gcc (Gentoo 9.2.0-r2 p3) 9.2.0
UPDATE2 : 같이, 어떤 처리 할 수있는 버전 요청 a
과 m
(테스트 입력 정수로 두 배 긴 정수 유형으로 구현 될 필요가 있습니다 당신은 또한 오버 플로우 정수 피하려면를)
int divisible_ui_p(unsigned int m, unsigned int a)
{
#if 1
/* handles even a */
int alpha = __builtin_ctz(a);
if (alpha) {
if (__builtin_ctz(m) < alpha) {
return 0;
}
a >>= alpha;
}
#endif
while (m > a) {
m += a;
m >>= __builtin_ctz(m);
}
if (m == a) {
return 1;
}
#if 1
/* ensures that 0 is divisible by anything */
if (m == 0) {
return 1;
}
#endif
return 0;
}
r
계산 하는 두 가지 가 실제로 서로 같다고 주장하는 테스트를보고 싶습니다 .
a % b
이 b
보다 훨씬 작다 a
. 테스트 케이스에서 대부분의 반복을 통해 비슷한 크기이거나 b
더 크며, 이러한 상황에서 많은 CPU에서 버전이 더 빠를 수 있습니다.