ฉันสังเกตเห็นสิ่งที่อยากรู้ในคอมพิวเตอร์ของฉัน *การทดสอบการหารด้วยลายมือเขียนเร็วกว่า%
ผู้ปฏิบัติงานอย่างมาก ลองพิจารณาตัวอย่างน้อยที่สุด:
* 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 หรือไม่ คุณทำแบบทดสอบนี้เร็วขึ้นได้ไหม
UPDATE: ตามที่ร้องขอนี่เป็นตัวอย่างที่ทำซ้ำได้น้อยที่สุด:
#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
ใหญ่กว่าและเวอร์ชันของคุณจะเร็วขึ้นสำหรับซีพียูจำนวนมากในสถานการณ์เหล่านั้น