รวมข้อควรระวังและข้อแนะนำในการเขียนโปรแกรม
Table of Contents
|
การใช้ #define
หลีกเลี่ยงการใช้ #define ให้ได้มากที่สุด โดยเฉพาะการกำหนดค่าคงที่ ใช้ const แทน
- นายโบ๊ต (นามสมมุติ) กำหนดค่า INF โดย #define INF -1u/2 (อ่านสารพัดค่า INF หากไม่เข้าใจ) เนื่องจาก -1u/2 เป็น unsigned จึงไม่สามารถติดลบได้ เมื่อเขาเรียกใช้ -INF จึงทำให้เกิดโศกนาฏกรรมขึ้น ทั้งๆที่ถ้าเขาใช้ const int INF = -1u/2; ก็จะไม่เกิดโศกนาฏกรรมแล้วแท้ๆ
- มาโคร #define MAX(_a,_b) ((_a > _b) ? _a : _b) ทำงานได้ดีเยี่ยมมาโดยตลอด จนกระทั่งเมื่อมีคนเรียกใช้ MAX(10, rand()) โค้ดจะเปลี่ยนจาก MAX(10, rand()) ไปเป็น ((10 > rand()) ? 10 : rand()) สมมุติว่าครั้งแรก rand() ออกมาได้ 11 และครั้งที่สอง rand() ออกมาได้ 9 จึงกลายเป็นว่าค่ามากสุดของ 10 และ 11 คือ 9 ??? อันที่จริงสำหรับ abs, max, min แนะนำให้ใช้ STL algorithm แทน
ค่าของ infinity
ควรใช้ค่า INF เป็น 109 + 21 เนื่องจากโจทย์ส่วนใหญ่บนโลกนี้ใช้ค่ามากสุดคือ 109 หรือ 109 + 7 ค่านี้จึงน่าจะมากพอที่จะเป็น INF ได้ ไม่ควรให้ INF = 231 - 1 ยกเว้นจำเป็นจริงๆ ตรวจสอบ datatype ของค่า INF ให้ดี และแนะนำให้ใช้ const กำหนดค่า INF
- ตัวอย่างเดิมของนายโบ๊ต (นามสมมุติ) กรุณาตรวจสอบให้ดีว่าค่า INF มี datatype ที่เหมาะสม
- ให้ INF = 231 - 1 หลังจากเขียน Floyd–Warshall algorithm เสร็จ ก็พบว่าโค้ดรันแล้วผิด เพราะบรรทัด
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
ได้ค่า d[i][j] เพี้ยน หลังจากวิเคราะห์จึงพบว่า d[i][k] = INF และ d[k][j] = INF ทำให้ d[i][k] + d[j][k] เกินค่าพิสัย int เกิด integer overflow และกลายเป็นค่าติดลบแทน !!! จากที่ d[i][j] ควรจะบ่งบอกว่าไม่มีทางจาก i ไป j เลยกลายเป็นมีค่าที่บอกว่ามีเส้นทาง(ที่น่าไปมากๆ) T^T
รับอักขระ
หลีกเลี่ยงการรับอักขระด้วย scanf "%c" ไปใช้ "%s" แทน
- %c รับทุกๆอย่างบนโลกใบนี้ ทั้ง '\n', ' ', EOF และทุกอย่างที่อยู่ขวางหน้ามัน จึงเป็นไปได้สูงมากๆที่การใช้ scanf "%c" จะได้ค่าไม่พึงประสงค์ออกมา ดังนั้นใช้ "%s" แทน "%c" ในทุกๆกรณี
STL list และ size()
ฟังก์ชั่น size() ใช้เวลา $O(n)$ นะ ไม่ใช่ $O(1)$ (อันที่จริง compiler บางตัวก็ $O(1)$ นะ)
เปรียบเทียบจำนวนจริง
หากจะเปรียบเทียบว่าจำนวนจริงสองตัวเท่ากันหรือไม่ (รวมถึง $\le$ และ $\ge$ ด้วย) แนะนำให้เขียนฟังก์ชั่นขึ้นมา
const double EPS = 1e-9; inline bool f_equal(double a, double b){ return abs(a - b) < EPS; }
โดย EPS คือค่าที่น้อยมากๆที่น้อยกว่าความแตกต่างที่น้อยที่สุดที่อาจเกิดขึ้นได้จากการเขียนโปรแกรมของเรา แต่ยังมากกว่ากว่าความผิดพลาดจากการแทนค่าจำนวนจริง
- 0.3 + 0.6 == 0.9 ?? คำตอบคือไม่ วิธีการแทนค่าจำนวนจริงทำให้ 0.3, 0.6, 0.9 คลาดเคลื่อนเล็กน้อย ดังนั้นเมื่อนำมาเปรียบเทียบกันจึงอาจไม่เท่ากัน
- 1/1000000000 != 1/2000000000 ??? คำตอบคือไม่ หากมี a, b, c, d ที่เป็นจำนวนเต็มหมด และต้องการเปรียบเทียบ a/b กับ c/d ว่าอะไรน้อยกว่า (หรือมากกว่า หรือเท่ากัน) ให้ใช้การคูณไขว้ ระวังการคูณไขว้เกิด integer overflow ด้วย
typedef long long ll; inline bool cmp(int a, int b, int c, int d) return ll(a) * ll(d) < ll(b) * ll(c);