หัวข้อ 71/91· การพัฒนาซอฟต์แวร์และการให้บริการดิจิทัล
การรวมต้นทุนที่ปลอดภัยต่อสกุลเงิน
การรวมรายการเงินจำนวนมาก — ใบแจ้งหนี้รายเดือน ต้นทุนรายสถานที่ ตัวเลขผลกระทบต่องบประมาณหลายปี — ด้วยเลขทศนิยมลอยตัวแบบไบนารีทั่วไป (f64) จะสะสมข้อผิดพลาดการแทนค่าเล็กน้อย เพราะเศษส่วนทศนิยมส่วนใหญ่ (เช่น $1,234.56) ไม่สามารถแทนค่าได้อย่างแม่นยำในทศนิยมลอยตัวแบบไบนารี ข้อผิดพลาดแต่ละรายการเล็กน้อย แต่แบบจำลองขนาดใหญ่ที่รวมหลายร้อยหรือหลายพันรายการตลอดหลายปีอาจคลาดเคลื่อนเป็นเศษส่วนของเซ็นต์ — และความคลาดเคลื่อนขึ้นอยู่กับ ลำดับ ของการบวก ทำให้ทำซ้ำไม่ได้ การรวมสกุลเงินที่ทำด้วยเลขคณิตทศนิยมที่แม่นยำ (หรือหน่วยย่อยที่สุดแบบจำนวนเต็ม) รวมได้อย่างแม่นยำ สอดคล้องกับวิธีที่ระบบบัญชีและการบัญชีคู่ต้องลงตัวถึงเซ็นต์
ทำไมจึงสำคัญ
นี่คือประเภทของบั๊กซอฟต์แวร์ที่มีเอกสารรองรับดีและเป็นพื้นฐาน: บทความของ Goldberg ปี 1991 ใน ACM Computing Surveys "What Every Computer Scientist Should Know About Floating-Point Arithmetic" เป็นเอกสารอ้างอิงมาตรฐานว่าทำไมทศนิยมลอยตัวแบบไบนารีจึงแทนค่าเงินทศนิยมส่วนใหญ่ไม่ได้อย่างแม่นยำ และทำไมการรวมค่าเหล่านั้นจำนวนมากจึงทบทวีความผิดพลาด แบบจำลองเศรษฐศาสตร์สุขภาพและการเงินของ NHS รวมหลายปีและหลายหมวดต้นทุนเป็นประจำ — ต้นทุนรวมของการเป็นเจ้าของและการวิเคราะห์ผลกระทบต่องบประมาณต่างก็รวมรายการต้นทุน f64 จำนวนมากตลอดช่วงเวลาหลายปี เมื่อแบบจำลองต้องลงตัวถึงเซ็นต์ — การตรวจสอบที่คำนวณยอดรวมด้วยมือต้องได้ตัวเลข เหมือนกันทุกประการ — เลขคณิตเองต้องเป็นทศนิยมที่แม่นยำ ไม่ใช่ทศนิยมลอยตัว
คณิตศาสตร์
การรวมแบบไร้เดียงสา: ยอดรวม = Σ f64(รายการ_i) — ความคลาดเคลื่อนที่ขึ้นกับลำดับ
การรวมที่ปลอดภัยต่อสกุลเงิน: ยอดรวม = Σ Decimal(รายการ_i) — แม่นยำ ทำซ้ำได้
การใช้การปรับด้วยเปอร์เซ็นต์ (เช่น กันสำรอง):
ปรับแล้ว = ยอดรวม × ตัวคูณ — ผลลัพธ์ Decimal ที่แม่นยำ อาจมีทศนิยม
มากกว่าเลขชี้กำลังหน่วยย่อยที่สุด
ของสกุลเงิน
ปัดแล้ว = ปัด(ปรับแล้ว, เลขชี้กำลังสกุลเงิน, กฎการปัด) — กฎการปัด (half-up
เทียบกับ half-even/การปัดแบบนายธนาคาร)
ต้องระบุอย่างชัดเจน
สังเกตวินัยสองขั้นตอน: การคูณจำนวน Decimal ที่แม่นยำด้วยตัวคูณอาจให้ทศนิยมมากกว่าที่สกุลเงินใช้จริง (เช่น ทศนิยมสามตำแหน่งจากจำนวนที่มีสองตำแหน่งคูณตัวคูณที่มีสองตำแหน่ง) — ความแม่นยำระหว่างทางนั้น จะไม่ ถูกปัดทิ้งโดยอัตโนมัติ มีเพียงขั้นตอนการปัดที่ชัดเจนพร้อมกฎการปัดที่ระบุเท่านั้นที่ลดมันลงสู่เลขชี้กำลังหน่วยย่อยที่สุดที่แท้จริงของสกุลเงิน
ตัวอย่างที่คำนวณแล้ว
ใบแจ้งหนี้รายเดือนที่เหมือนกันสิบสองใบ ใบละ $1,234.56 รวมด้วยเลขคณิตทศนิยมที่แม่นยำ: $1,234.56 × 12 = $14,814.72 พอดี เทียบกับการรวมค่าคงที่ f64 1234.56 สิบสองครั้งในความแม่นยำสองเท่าตาม IEEE-754 ซึ่งอาจคลาดเคลื่อนเป็นเศษส่วนของเซ็นต์ขึ้นกับลำดับการรวม — ประเภทของบั๊กที่เกิดขึ้นจริงและมีเอกสารรองรับ ไม่ใช่ปัญหาสำหรับแบบจำลองที่สร้างบนเลขคณิต Money ทศนิยมที่แม่นยำ
ทีนี้ใช้กันสำรองผลกระทบต่องบประมาณมาตรฐาน 5% (ตัวคูณ 1.05) กับยอดรวม $14,814.72 นั้น: $14,814.72 × 1.05 = $15,555.456 — ทศนิยมสามตำแหน่ง เพราะการคูณแม่นยำและไม่ถูกปัดโดยอัตโนมัติเป็นสองตำแหน่งของสกุลเงิน เมื่อปัดเป็น 2 ตำแหน่งอย่างชัดเจนด้วยการปัดแบบนายธนาคาร (half-even) ได้ $15,555.46 พอดี
ความเชื่อมโยงกับวิศวกรรมซอฟต์แวร์
นี่คือบทเรียนพื้นฐานโดยตรงเบื้องหลังหลักการที่ว่า "ซอฟต์แวร์การเงินใช้ Decimal ไม่ใช่ float" — เชื่อมโยงอย่างชัดเจนกับโมดูลต้นทุนรวมของการเป็นเจ้าของและการวิเคราะห์ผลกระทบต่องบประมาณของคลังนี้ ซึ่งปัจจุบันทั้งสองรวมต้นทุนทศนิยมลอยตัวธรรมดา ข้อโต้แย้งเรื่องความถูกต้องไม่ได้เรียกร้องให้ย้ายแบบจำลองเหล่านั้นทันที แต่ระบุอย่างแม่นยำว่า เมื่อใด ที่ระบบต้องลงตัวถึงเซ็นต์ และจึงต้องไม่ใช้ทศนิยมลอยตัวแบบไบนารีสำหรับเลขคณิตเงินของตน ดูการจัดสรรต้นทุนแบบเป๊ะถึงเซ็นต์ สำหรับปัญหาคู่กันคือการแบ่ง (แทนการรวม) ยอดรวมโดยไม่เสียเซ็นต์
ข้อผิดพลาดที่พบบ่อย
- แปลงเป็น
floatกลางห่วงโซ่: การดึงค่าเงินออกเป็นเลขทศนิยมลอยตัวระหว่างการคำนวณ (ไลบรารีMoneyบางตัวถึงกับตั้งชื่อเมธอดแปลงนี้ว่า "lossy" เป็นคำเตือนที่ชัดเจน) ทิ้งการรับประกันความแม่นยำอย่างเงียบๆ สำหรับทุกการคำนวณหลังจุดนั้น - "Decimal ช้าเกินกว่าจะสนใจ": การปัดตก เลขคณิตทศนิยมที่แม่นยำว่าเป็นภาระที่ไม่จำเป็น ทั้งที่การรายงานทางการเงินต้องการความถูกต้องและการตรวจสอบได้ ไม่ใช่ปริมาณงานดิบ
- ใช้เปอร์เซ็นต์กันสำรองโดยไม่ระบุกฎการปัด: half-up เทียบกับ half-even (การปัดแบบนายธนาคาร) อาจเปลี่ยนเซ็นต์สุดท้าย; ข้อตกลงการปัดเองต้องเป็นทางเลือกที่ระบุไว้และตรวจสอบได้ — ดูการวิเคราะห์ต้นทุนผลประโยชน์สำหรับแนวทาง Green Book ของ HM Treasury เกี่ยวกับการปรับกันสำรองและอคติแง่ดี ซึ่งเป็นตัวเลขประเภทที่ขั้นตอนการปัดนี้นำไปใช้
แหล่งที่มา
- Fowler M. "Patterns of Enterprise Application Architecture." Addison-Wesley, 2002 — รูปแบบ
Money. - Goldberg D. "What Every Computer Scientist Should Know About Floating-Point Arithmetic." ACM Computing Surveys, 1991.
- HM Treasury, The Green Book — แนวทางเรื่องอคติแง่ดีและกันสำรองสำหรับการสร้างแบบจำลองผลกระทบต่องบประมาณ. https://www.gov.uk/government/publications/the-green-book-appraisal-and-evaluation-in-central-government/the-green-book-2020