ยอดเงินไม่ได้คำนวณผิด มันแค่ปัดเศษในที่ที่เรามองไม่เห็น
เงินไม่ใช่ทศนิยม เก็บเป็นจำนวนเต็มของสตางค์ คิดด้วยจำนวนเต็มตลอดสาย ปัดเศษที่เดียวตอนแสดง แล้วเทสต์ด้วยราคามีเศษ ไม่ใช่เลขกลม ๆ ที่ผ่านตลอดไป
บัญชีทักมาว่ายอดรวมไม่ตรง หนึ่งสตางค์
หนึ่งสตางค์ ฟังดูไม่เป็นไร แต่ปิดงบไม่ได้ ตัวเลขสองฝั่งต้องตรงกันเป๊ะ ไม่งั้นไม่ผ่าน
เปิดดูออร์เดอร์นั้น กดคิดใหม่เอง ได้ตัวเลขที่ถูก ลองสร้างออร์เดอร์ทดสอบสิบอัน ตรงหมดทุกอัน
แล้วก็สรุปกับตัวเองว่าคงเป็นที่ระบบบัญชีเขา
ไม่ใช่ที่ระบบเขา
เปิด console ขึ้นมา พิมพ์ 0.1 + 0.2 แล้วกด enter
ได้ 0.30000000000000004
อันนี้ไม่ใช่บั๊กของภาษา มันเป็นแบบนี้ในเกือบทุกภาษาบนโลก เพราะเลขทศนิยมแบบที่เครื่องเก็บ มันเก็บเศษส่วนบางค่าให้ตรงเป๊ะไม่ได้ เหมือนเราเขียน 1/3 เป็นทศนิยมให้จบไม่ได้
ที่เราไม่เคยเจอ เพราะข้อมูลทดสอบของเราเป็นเลขกลม ๆ ร้อยบาท ห้าสิบบาท ยี่สิบห้า
ลูกค้าจริงซื้อของราคา 129.90 สามชิ้น ลดสิบเปอร์เซ็นต์ แล้วหารสามคนจ่าย
เศษมันไปโผล่ตรงนั้น
หลักการมีข้อเดียว
เงินไม่ใช่ตัวเลขทศนิยม เงินคือจำนวนเต็มของหน่วยที่เล็กที่สุด
ในไทยคือสตางค์ 129.90 บาท เก็บเป็น 12990
คิดเลขทั้งหมดด้วยจำนวนเต็ม แล้วค่อยหารร้อยตอนจะเอาขึ้นจอ
ทำจริงมีสามชั้น แต่ละชั้นทำหน้าที่ต่างกัน
ชั้นแรก ฐานข้อมูลห้ามใช้ชนิด float
ใช้ integer เก็บสตางค์ หรือใช้ decimal ที่ระบุจำนวนหลักชัดเจนไปเลย ถ้าตอนนี้เป็น float อยู่ อันนี้คือของที่ต้องย้ายก่อนข้อมูลจะเยอะกว่านี้
ชั้นที่สอง คิดเลขด้วยจำนวนเต็มตลอดสาย
บวกลบคูณด้วยสตางค์ ไม่ใช่บาท ยิ่งมีหลายขั้น ลดแล้วบวกภาษีแล้วหาร ยิ่งต้องอยู่ในจำนวนเต็มให้นานที่สุด
ชั้นที่สาม ปัดเศษที่เดียว แล้วเขียนไว้ว่าปัดยังไง
ปัดขึ้น ปัดลง หรือปัดครึ่ง เลือกมาหนึ่งอย่างแล้วใช้อันเดียวกันทั้งระบบ ที่พังบ่อยที่สุดไม่ใช่การปัดเศษ แต่คือปัดคนละแบบในสองที่ แล้วเอาผลมาเทียบกัน
จำง่าย ๆ เก็บเป็นจำนวนเต็ม คิดเป็นจำนวนเต็ม ปัดครั้งเดียวตอนแสดง
ทีนี้เรื่องที่เกี่ยวกับ AI โดยตรง
บอก AI ว่า "คิดยอดรวมให้หน่อย" มันจะเขียน price * quantity * 0.9 ให้ทันที
มันถูกตามที่เราขอ และมันจะผ่านทุกเทสต์ที่เราเขียน เพราะเราก็ใส่เลขกลม ๆ เข้าไปเหมือนกัน
มันจะไม่เปลี่ยนไปใช้จำนวนเต็มให้เอง ถ้าเราไม่บอก เพราะเราไม่ได้ขอ และเพราะคนที่ขอส่วนใหญ่ก็ไม่รู้ว่าต้องขอ
เอาไปใช้วันนี้ เริ่มจากทดสอบก่อน
เปิด console พิมพ์ 0.1 + 0.2 ดูก่อนหนึ่งที ให้เห็นกับตา
แล้วไปหน้าที่คิดเงินในแอปตัวเอง ใส่ของราคาที่มีเศษ เช่น 129.90 สามชิ้น แล้วลดเปอร์เซ็นต์ ดูว่ายอดที่โชว์กับยอดที่เก็บลงฐานข้อมูลตรงกันไหม
แล้วบอก AI แบบนี้
ไล่เรื่องเงินในโปรเจกต์นี้ให้หน่อย
- database: เปลี่ยนคอลัมน์เงินจาก float เป็น integer (เก็บเป็นสตางค์) หรือ decimal ที่ระบุหลัก
- คำนวณ: บวกลบคูณหารด้วยจำนวนเต็มตลอด อย่าแปลงเป็นทศนิยมกลางทาง
- ปัดเศษ: ทำที่เดียว ตอนจะแสดงผล แล้วเขียน comment ไว้ว่าใช้กฎไหน
- เขียนเทสต์ที่ใช้ราคามีเศษ เช่น 129.90 x 3 ลด 10% หาร 3 คน แล้ว assert ว่าผลรวมเท่ากับยอดเต็มพอดี
ข้อสุดท้ายสำคัญที่สุด ถ้าเทสต์ใส่แต่เลขกลม มันจะผ่านตลอดไป แล้วเราจะไปเจอตอนบัญชีปิดงบไม่ได้