การสำรวจทางเลือกแทนเครื่องหมาย %
(Modulus) ใน C/C++ เพื่อการเขียนโปรแกรมที่มีประสิทธิภาพ
เมื่อเขียนโปรแกรมใน C หรือ C++ นักพัฒนามักจะใช้เครื่องหมาย modulus %
เพื่อทำการคำนวณที่ต้องการเศษจากการหาร อย่างไรก็ตาม ในสภาพแวดล้อมเฉพาะ เช่น อุปกรณ์ฝังตัวขนาดเล็ก — โดยเฉพาะอย่างยิ่งที่ใช้ไมโครคอนโทรลเลอร์ขนาด 8 บิต — เครื่องหมาย %
อาจทำให้ประสิทธิภาพลดลงอย่างมาก ในบทความนี้ เราจะสำรวจทางเลือกที่มีประสิทธิภาพแทนเครื่องหมาย %
และเจาะลึกถึงเหตุผลเบื้องหลังความมีประสิทธิภาพเหล่านั้น
ปัญหากับเครื่องหมาย Modulus
แม้ว่าเครื่องหมาย modulus จะดูเหมือนง่ายในทฤษฎี แต่ปัญหาจริงอาจเกิดขึ้นได้อย่างมีนัยสำคัญ ระบบฝังตัวขนาดเล็กหลายแห่งขาดฮาร์ดแวร์ที่สามารถทำการหารได้ ทำให้การทำงานบนเครื่องหมาย modulus ช้าและไม่มีประสิทธิภาพ
การเข้าใจการสูญเสียประสิทธิภาพ
- ประสิทธิภาพ: การดำเนินการ modulus อาจช้าถึง 5 ถึง 10 เท่าของการหารจำนวนเต็มที่เรียบง่าย
- ข้อจำกัดด้านฮาร์ดแวร์: ในไมโครคอนโทรลเลอร์ที่ไม่มีคำสั่งการหาร ทางเลือกอื่น เช่น การรักษาตัวนับหรือตัวแปรสถานะ อาจหลีกเลี่ยงไม่ได้แต่ไม่ใช่ตัวเลือกที่ดีที่สุด
มาดูตัวอย่างเฉพาะเพื่อเน้นปัญหานี้:
const int FIZZ = 6;
for (int x = 0; x < MAXCOUNT; x++) {
if (!(x % FIZZ)) print("Fizz\n"); // ช้าในบางระบบ
}
กลยุทธ์ทางเลือก
วิธีการที่ติดอยู่คือการรักษาตัวแปรนับที่รีเซ็ตด้วยตนเองเมื่อเกินขอบเขต:
const int FIZZ = 6;
int fizzcount = 1;
for (int x = 1; x < MAXCOUNT; x++) {
if (fizzcount >= FIZZ) {
print("Fizz\n");
fizzcount = 0;
}
}
วิธีนี้ทำงานได้เร็วกว่าและตัดการดำเนินการ modulus ออก ทำให้ประสิทธิภาพของโปรแกรมยังคงดีอยู่
ทางเลือกแทนเครื่องหมาย %
ในการค้นหาความมีประสิทธิภาพ เราจะพูดถึงแนวคิดทางคณิตศาสตร์และเทคนิคที่ให้ผลลัพธ์โดยไม่ต้องใช้เครื่องหมาย modulus ตรงๆ
การใช้ฐานของตัวเลข
หนึ่งในวิธีที่มีประสิทธิภาพคือการใช้คุณสมบัติของฐานตัวเลข:
-
การแยก: แยกหมายเลขโดยใช้การแทนฐานของมัน ทำให้คำนวณเศษได้ง่ายขึ้นโดยไม่ต้องหาร
-
การคำนวณตัวอย่าง: หากเรามีวันในสัปดาห์ที่แทนด้วย
DOW
ในจำนวนเต็ม 16 บิต เราสามารถเขียนการคำนวณสำหรับDOW % 7
ใหม่ได้ดังนี้:
DOW = DOW_HI * 256 + DOW_LO
DOW % 7 = ((DOW_HI * 256) % 7 + (DOW_LO % 7)) % 7
ด้วยวิธีนี้ คุณสามารถคำนวณส่วนต่างๆ ของหมายเลขแยกกัน ซึ่งนำไปสู่การลดจำนวนการคำนวณ
ตัวอย่างการนำไปใช้โดยตรง
การใช้การดำเนินการแบบบิตสามารถทำให้การคำนวณง่ายขึ้นได้อย่างมาก ดังที่เห็นในด้านล่าง:
unsigned char Mod7Byte(unsigned char X) {
X = (X & 7) + ((X >> 3) & 7) + (X >> 6);
X = (X & 7) + (X >> 3);
return X == 7 ? 0 : X; // รับประกันว่าช่วงจะถูกบำรุงรักษา
}
การทดสอบอัลกอริธึม
เพื่อยืนยันว่าการนำไปใช้ของเราทำงานอย่างถูกต้อง เราสามารถสร้างลูปทดสอบง่ายๆ ได้:
clrf x
clrf count
TestLoop:
movf x,W
RCALL Mod7Byte
cpfseq count
bra fail
incf count,W
xorlw 7
skpz
xorlw 7
movwf count
incfsz x,F
bra TestLoop
passed:
สรุป
โดยสรุป การเพิ่มประสิทธิภาพเครื่องหมาย %
ต้องเข้าใจกลไกพื้นฐานของการดำเนินการทางคณิตศาสตร์และนำเทคนิคการเขียนโปรแกรมที่มีประสิทธิภาพมาใช้ โดยเฉพาะในสภาพแวดล้อมที่มีข้อจำกัดด้านทรัพยากร การใช้การคำนวณทางเลือกสามารถประหยัดรอบการทำงานอันมีค่าบนระบบฝังตัว เพิ่มประสิทธิภาพรวมทั้งหมด
ครั้งต่อไปที่คุณใช้ %
ลองพิจารณาทางเลือกเหล่านี้เพื่อให้แอปพลิเคชัน C/C++ ของคุณทำงานอย่างรวดเร็วโดยไม่เกิดข้อผิดพลาดด้านประสิทธิภาพ
โปรดแสดงความคิดเห็นหรือแบ่งปันทางเลือกอื่น ๆ ที่คุณใช้!