การสำรวจทางเลือกแทนเครื่องหมาย % (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 ตรงๆ

การใช้ฐานของตัวเลข

หนึ่งในวิธีที่มีประสิทธิภาพคือการใช้คุณสมบัติของฐานตัวเลข:

  1. การแยก: แยกหมายเลขโดยใช้การแทนฐานของมัน ทำให้คำนวณเศษได้ง่ายขึ้นโดยไม่ต้องหาร

  2. การคำนวณตัวอย่าง: หากเรามีวันในสัปดาห์ที่แทนด้วย 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++ ของคุณทำงานอย่างรวดเร็วโดยไม่เกิดข้อผิดพลาดด้านประสิทธิภาพ


โปรดแสดงความคิดเห็นหรือแบ่งปันทางเลือกอื่น ๆ ที่คุณใช้!