ไม่นี่ไม่ใช่คำถาม"ทำไมจึงเป็น (1 / 3.0) * 3! = 1"
ฉันได้อ่านเกี่ยวกับคะแนนจำนวนมากเมื่อเร็ว ๆ นี้; วิธีการคำนวณเดียวกันอาจให้ผลลัพธ์ที่แตกต่างกันในการตั้งค่าสถาปัตยกรรมหรือการเพิ่มประสิทธิภาพที่แตกต่างกัน
นี่เป็นปัญหาสำหรับวิดีโอเกมที่เก็บรีเพลย์หรือเครือข่ายเพียร์ทูเพียร์ (ตรงข้ามกับเซิร์ฟเวอร์ - ไคลเอนต์) ซึ่งพึ่งพาลูกค้าทั้งหมดที่สร้างผลลัพธ์เดียวกันทุกครั้งที่รันโปรแกรม - ความคลาดเคลื่อนเล็กน้อยในหนึ่งเดียว การคำนวณ floating-point สามารถนำไปสู่สถานะเกมที่แตกต่างกันอย่างมากบนเครื่องที่แตกต่างกัน (หรือแม้แต่ในเครื่องเดียวกัน! )
นี้เกิดขึ้นแม้กระทั่งในหมู่ประมวลผลว่า "ตาม" มาตรฐาน IEEE-754หลักเพราะบางหน่วยประมวลผล (คือ x86) ใช้ความแม่นยำขยายคู่ นั่นคือพวกเขาใช้การลงทะเบียน 80 บิตเพื่อทำการคำนวณทั้งหมดจากนั้นตัดเป็น 64- บิตหรือ 32 บิตซึ่งนำไปสู่ผลลัพธ์การปัดเศษที่แตกต่างกันกว่าเครื่องที่ใช้ 64- บิตหรือ 32- บิตสำหรับการคำนวณ
ฉันเห็นวิธีแก้ไขปัญหาออนไลน์หลายวิธี แต่ทั้งหมดสำหรับ C ++ ไม่ใช่ C #:
- ปิดใช้งานโหมดขยายความแม่นยำสองเท่า (เพื่อให้การ
double
คำนวณทั้งหมดใช้ IEEE-754 64- บิต) โดยใช้_controlfp_s
(Windows),_FPU_SETCW
(Linux?) หรือfpsetprec
(BSD) - เรียกใช้คอมไพเลอร์เดียวกันด้วยการตั้งค่าการปรับให้เหมาะสมที่สุดเสมอและกำหนดให้ผู้ใช้ทุกคนมีสถาปัตยกรรม CPU เดียวกัน (ไม่มีการเล่นข้ามแพลตฟอร์ม) เนื่องจาก "คอมไพเลอร์" ของฉันเป็นจริง JIT ซึ่งอาจปรับให้เหมาะสมแตกต่างกันทุกครั้งที่รันโปรแกรมฉันไม่คิดว่ามันเป็นไปได้
- ใช้เลขคณิตจุดคงที่และหลีกเลี่ยง
float
และdouble
ทั้งหมดdecimal
จะทำงานเพื่อจุดประสงค์นี้ แต่จะช้ากว่านี้มากและไม่มีSystem.Math
ฟังก์ชันไลบรารีใดสนับสนุน
ดังนั้นนี่เป็นปัญหาใน C # หรือไม่ ถ้าฉันตั้งใจจะสนับสนุน Windows เท่านั้น (ไม่ใช่ Mono)
ถ้าเป็นเช่นนั้นมีวิธีใดที่จะบังคับให้โปรแกรมของฉันทำงานที่ความแม่นยำสองเท่าปกติหรือไม่?
ถ้าไม่มีมีห้องสมุดใดบ้างที่จะช่วยให้การคำนวณจุดลอยตัวสอดคล้องกันหรือไม่
strictfp
คำหลักซึ่งบังคับให้ทำการคำนวณทั้งหมดในขนาดที่ระบุ ( float
หรือdouble
) มากกว่าขนาดที่ขยาย อย่างไรก็ตาม Java ยังคงมีปัญหามากมายกับการรองรับ IEE-754 ภาษาการเขียนโปรแกรมน้อยมาก (มาก, มาก) รองรับ IEE-754