เกี่ยวกับความแม่นยำของ floating point และทำไมเราถึงยังใช้มันอยู่


38

จุดลอยตัวนั้นมักจะลำบากสำหรับความแม่นยำในโลกขนาดใหญ่

นี้บทความอธิบายเบื้องหลังฉากและข้อเสนอที่เห็นได้ชัดทางเลือก - ถาวรหมายเลขจุด ข้อเท็จจริงบางอย่างน่าประทับใจจริง ๆ เช่น:

"ความแม่นยำ 64 บิตนำคุณไปสู่ระยะทางไกลที่สุดของพลูโตจากดวงอาทิตย์ (7.4 พันล้านกิโลเมตร) ด้วยความแม่นยำซับไมโครมิเตอร์"

ความแม่นยำของ sub-micrometer นั้นมากกว่าความต้องการ fps ใด ๆ (สำหรับตำแหน่งและแม้แต่ความเร็ว) และมันจะช่วยให้คุณสร้างโลกที่ยิ่งใหญ่ได้

คำถามของฉันคือทำไมเรายังคงใช้จุดลอยตัวถ้าจุดคงที่มีข้อดีดังกล่าว? API การแสดงผลและห้องสมุดฟิสิกส์ส่วนใหญ่ใช้จุดลอยตัว (และประสบกับข้อเสียดังนั้นผู้พัฒนาจึงต้องหลีกเลี่ยง)

พวกมันช้ากว่านี้ไหม?

นอกจากนี้คุณคิดว่าเอ็นจิ้นดาวเคราะห์ที่ปรับขนาดได้เช่น outerra หรืออินฟินิตี้จัดการกับขนาดใหญ่ได้อย่างไร พวกเขาใช้จุดคงที่สำหรับตำแหน่งหรือมีอัลกอริทึมการแบ่งพื้นที่บางส่วนหรือไม่?


3
บิต "เพิ่มเติม" ล่าสุดอาจเป็นคำถามแยกต่างหากดังนั้นคำถามหลักจะไม่ถูกแยกออกจากกัน
Tetrad

ฉันต้องการคิดวิธีบังคับจุดคงที่ ... เกมของฉันมีข้อผิดพลาดแปลก ๆ ทุกประเภทเพราะ Lua ใช้ FPU และ DirectX fiddles กับ FPU ด้วย ... ฉันเห็นสิ่งต่าง ๆ เช่น 2 * 9000 = 17995 หรือ 500 * 10 = 4897 มันโง่จริงๆ แต่ข้อผิดพลาดที่แย่ที่สุดน่าจะเป็นสิ่งที่กล่าวถึงในฟอรัม Ogre3D โดยที่ 1 + 5 = 4
speeder

3
ไม่ปรับความคิดเห็น แต่ถ้าคุณตัดสินใจใช้จุดคงที่ Q-Floats ( en.wikipedia.org/wiki/Q_(number_format) ) เป็นเพื่อนของคุณ มีความรวดเร็วและใช้งานง่าย
Jonathan Dickinson

ดังนั้นเพื่อสรุป¿ฉันควรจะติดกับจุดลอยตัว (ถ้าฉันทำงานใน Java หรือ Python)? - Gastón 26 นาทีที่แล้ว
Gastón

คำตอบ:


20

หากคุณจะอนุญาตให้ฉันเสียบที่ไร้ยางอายฉันจะให้ตัวอย่างจากเกมจริงที่ฉันกำลังทำงานอยู่ (ลิงก์วิดีโอ YouTube)

เกมดังกล่าวมีโลกที่ไม่มีที่สิ้นสุดและสร้างขึ้นบนเครื่องมือฟิสิกส์ มันใช้จุดลอยตัวที่มีความแม่นยำเดียว หลังจากพื้นที่เกมไม่กี่ร้อยเมตรปัญหาความแม่นยำเริ่มเกิดขึ้น (และยิ่งแย่ลงไปกว่าเดิมจากจุดกำเนิดที่คุณได้รับ)

ทางออกของฉัน? ทุก ๆ 200m หรือมากกว่านั้นฉันจะย้ายโลกทั้งใบกลับไปที่จุดกำเนิด 200 เมตร (หากคุณสนใจที่จะค้นหาและลองต้นแบบตัวใดตัวหนึ่งในเว็บไซต์ของฉันและนำ [w] orld debug overlay มาใส่คุณจะเห็นสิ่งนี้เกิดขึ้น)

ทำไมไม่ใช้จุดคงที่? หรือความแม่นยำสองเท่า แทนที่จะเป็นความแม่นยำเดียว? เพราะทุกอย่างอื่นกำลังใช้จุดลอยน้ำที่มีความแม่นยำเดียว

เอนจิ้นฟิสิกส์ที่ฉันใช้ใช้มัน XNA ใช้ข้อมูลที่ได้รับการโหลดลงบนการ์ดกราฟิกนั้นถูกจัดรูปแบบเป็นทศนิยมที่มีความแม่นยำเดียว แม้ภาษาตัวเองถูกออกแบบมาเพื่อการทำงานที่มีหมายเลขจุดลอย - การเขียนและ (ที่สำคัญกว่า) อ่านอยู่ไกลง่ายกว่า0.5f0x80000000L

เป็นเพียงเรื่องของการปฏิบัติที่ง่ายขึ้น และผู้ชนะที่ชัดเจนคือการรับรู้ถึงปัญหาความแม่นยำของจุดลอยตัวและการเขียนฟังก์ชั่น "ย้ายโลกกลับไปสู่ศูนย์" ค่อนข้างง่าย (หรือใช้การแบ่งพื้นที่ว่าง

และในที่สุดอีกตัวอย่างหนึ่ง - Orbiterคือเกม (จำลองจริง ๆ ) ที่ต้องใส่ใจเกี่ยวกับความแม่นยำ ไม่เพียงแค่อยู่ในอวกาศ แต่ยังทันเวลา (เร่งความเร็วเวลารวมทั้งวัตถุที่กำลังโคจรอยู่ - ไม่ต้องการให้พวกมันหล่นลงมาจากท้องฟ้าตอนนี้) นอกจากนี้ยังใช้หมายเลขจุดลอยตัวและใช้แฮ็คเพื่อรักษาเสถียรภาพ


ฉันสงสัยอยู่เสมอว่ามันอาจจะง่ายกว่าที่แอปพลิเคชั่นบางอย่างจะย้ายทุกอย่างและเก็บ "ผู้เล่น" ไว้ที่จุดเริ่มต้น สนใจดูฉันไม่ใช่คนเดียว!
dash-tom-bang

ฉันชอบเหตุผลของคุณ ฉันแค่อยากจะชี้ให้เห็นว่าเมื่อพูดถึงเกมที่เกี่ยวข้องกับเครือข่ายจุดคงที่ดูเหมือนว่าจะมีนิสัยใจคอ / ความเบี่ยงเบนน้อยกว่า (การทำนายลูกค้ามีความแม่นยำมากกว่า)
Jonathan Dickinson

ฉันไม่เข้าใจข้อโต้แย้งของคุณเป็นอย่างดี แล้วทำไมยังไม่มีภาษากำหนดจุดคงที่ไว้? แน่นอนว่าน่าจะเป็นเหตุผลที่ดึงดูดให้ใช้ทุ่นลอย แต่นั่นไม่ได้อธิบายว่าทำไมจุดคงที่จึงไม่ถูกใช้งานทุกที่
jokoon

@ jokoon ฉันคิดว่าคำตอบของฉันค่อนข้างชัดเจน ทำไมถึงไม่แก้ไขจุดคงที่ทุกที่? เพียงมองไปที่ Wikipedia: "ภาษาคอมพิวเตอร์มีเพียงไม่กี่ภาษาที่มีการสนับสนุนค่าจุดคงที่ในตัวเพราะสำหรับแอพพลิเคชั่นส่วนใหญ่การแทนค่าทศนิยมแบบเลขฐานสองหรือทศนิยมมักจะง่ายต่อการใช้งานและแม่นยำเพียงพอ " นักออกแบบที่ดีรู้ว่าควรละเว้นอะไร - และสิ่งที่ทำซ้ำหน้าที่การใช้งานในลักษณะที่ทำให้ง่ายสำหรับโปรแกรมเมอร์ที่จะถ่ายภาพตัวเองในเท้าเป็นผู้สมัครที่ดี
Andrew Russell

ตกลง โปรเซสเซอร์ของวันนี้รันคำสั่งเลขทศนิยมได้ง่ายมากคำสั่งนั้นมีปริมาณงานที่ดีเยี่ยมและส่วนใหญ่มีความหน่วงแฝงที่นานกว่าไม่กี่รอบ
doug65536

11

ครั้งแรก - ใช่มันเร็วกว่ามาก แม้ว่าคุณจะสามารถทำให้จุดคงที่ทำงานได้เร็วเท่ากับ FPU "ปกติ" จุดลอยตัวที่แท้จริงมีคำแนะนำที่เป็นประโยชน์เช่น fsel เพื่อหยุดการแตกแขนงหรือ SIMD เพื่อทำงานกับหลาย ๆ อันในคราวเดียว GPUs ใช้จุดลอยอย่างน้อยในส่วนติดต่อผู้ใช้ของพวกเขา

ประการที่สอง 64 บิตทำให้คุณอยู่ในจุดลอยตัวเช่นกัน - คนส่วนใหญ่ยังคงใช้ 32 แต่ข้อดีหลักคือมันปรับขนาดได้ มาตราส่วนจุดคงที่นั้นมีความแม่นยำคงที่ ไม่ว่าคุณจะวัดดวงอาทิตย์ถึงดาวพลูโตหรือฝั่งตรงข้ามคุณจะได้รับความแม่นยำแบบเดียวกัน จุดลอยตัวจะให้ผลลัพธ์ที่แม่นยำมากขึ้นเมื่อค่าทั้งหมดที่เกี่ยวข้องมีค่าน้อยลง เนื่องจากห้องสมุดฟิสิกส์ทั่วไปคาดว่าจะทำงานได้อย่างช้าๆโดยมีเกมจำนวนมากในระดับที่แตกต่างกันและบางเกมอาจมีขนาดที่แตกต่างกันอย่างมาก - พวกเขาจำเป็นต้องใช้หมายเลขที่ทำงานได้ในหลายระดับ


5

อีกประเด็นสำคัญที่ควรทำคือการลอยตัวนั้นไม่ถูกต้องเหมือนคนที่นี่ ทุ่น 32 บิตมีความแม่นยำเต็มจำนวน 24 บิต ซึ่งหมายความว่าอย่างน้อยมีความแม่นยำเท่ากับค่าจุดคงที่ 24 บิตสำหรับช่วงที่กำหนด ในขณะที่ลอยได้รับความแม่นยำน้อยกว่าค่าที่มากขึ้นจะกลายเป็นค่าคงที่ของจุดจะล้นและล้อมรอบในบางจุด การลดความแม่นยำเป็นทางเลือกที่ดีกว่า ลอยอาจล้น แต่ไกลไปไกลในภายหลัง ฉันอยากเห็นใบหน้าของคุณเมื่อโลกของคุณโอบล้อมไปถึง -2 ^ 31 เนื่องจากมีจุดคงที่มากเกินไป

ค่าเลขทศนิยม 64 บิตมีความแม่นยำจำนวนเต็ม 53 บิตดังนั้นจึงแม่นยำมาก


ค่าทศนิยมจะไม่ล้น ถ้าผลลัพธ์ของการคำนวณมีขนาดใหญ่เกินกว่าที่จะแสดงได้ผลลัพธ์ก็คือค่าบวกหรือลบไม่มีที่สิ้นสุด
Pineapple

3

ในบริบท FPS ค่าจุดคงที่จริงอาจเป็นความรับผิดชอบ จุดลอยตัวใกล้กับศูนย์มีความแม่นยำมากกว่า มันเป็นเพียงในระยะทางขนาดใหญ่จุดคงที่จะกลายเป็นที่นิยมมากขึ้น คำตอบนั้นขึ้นอยู่กับบริบท

ในกาแลคซีอย่างคุณสามารถใช้กรอบอ้างอิง ใช้ขนาดใหญ่สำหรับระบบสุริยจักรวาลแล้วใช้จุดศูนย์กลางของดวงอาทิตย์ (หรือจุดที่คล้ายกัน) เป็นจุดกำเนิดของสิ่งต่าง ๆ ภายในระบบ การใช้ระบบนี้คุณสามารถมีเค้กของคุณและกินเพื่อพูดและไม่ยากที่จะจินตนาการ

IIRC ผู้พัฒนาอนันต์อินฟินิตี้ระบุว่าเขากำลังวนซ้ำประเด็นปัญหาอย่างต่อเนื่องในการสัมภาษณ์ครั้งหนึ่งของเขา


ไม่น่าเป็นไปได้ว่าในเกมใด ๆ คุณจะต้องมีความแม่นยำ "ใกล้ถึงศูนย์" ของจุดลอย หากคุณมีหน่วยหนึ่งเมตรความแม่นยำ 10 บิตจะช่วยให้คุณมีความแม่นยำในระดับย่อยและยังช่วยให้คุณจำลองแบบในแต่ละทิศทางได้มากกว่า 4,000 กิโลเมตรในแต่ละทิศทางหากคุณมีค่า 32 บิต หากคุณต้องการความแม่นยำมากกว่ามิลลิเมตรคุณสามารถเลื่อนบิตอีกสองสามบิตได้อย่างแน่นอน การย้ายค่า 64 บิตในเกมอวกาศจะทำให้ระบบพลังงานแสงอาทิตย์ (หรือมากกว่านั้น) มีความแม่นยำคงที่ตลอดทั้งโวลุ่ม
dash-tom-bang

จริง และนั่นเป็นเหตุผลที่คุณจะใช้ดวงอาทิตย์ของระบบสุริยะเป็นจุดอ้างอิงในโลกขนาดกาแล็กซี่! ประเด็นก็คือวิธีการจัดการความแม่นยำที่คุณเลือกไม่ได้นำอะไรมาสู่ตารางอย่างใดอย่างหนึ่ง มันเป็นสิ่งที่สงสัยดังนั้นคุณอาจใช้ห้องสมุด / ฮาร์ดแวร์ของคุณเข้าร่วม
Rushyo

อนึ่งฉันทำงานในเกมที่เราต้องทำแบบจำลองมากกว่า 4,000 กม. ในแต่ละทิศทาง สำหรับความเข้ากันได้กับรหัสในโครงการอื่น ๆ มันต้องใช้ 32 บิตสำหรับตำแหน่ง มันไม่ใช่ปัญหาเชิงทฤษฎีเนื่องจากความต้องการเชิงพาณิชย์ที่วางอยู่บนการนำโค้ดกลับมาใช้ใหม่และขนาดของโลกเกมในปัจจุบัน

1

หากคุณยังไม่ได้คุณควรตรวจสอบการสอนของPlanet Renderingบน GameDev.net สำหรับการแบ่งพื้นที่นั้นทางออกหนึ่งคือการรักษาตัวแปรตำแหน่งสองแบบแยกกันคือหนึ่งสเกลมาโครและสเกลไมโครหนึ่งตัว วิธีนี้ใช้งานได้ค่อนข้างดี (ทดสอบ)

วิธีแก้ปัญหาที่แน่นอนนั้นขึ้นอยู่กับว่าคุณวางแผนที่จะจัดการกับระยะทางไกลในเครื่องยนต์หรือไม่ - คุณวางแผนที่จะกระโดดข้ามประตูหรือบีบอัดเวลาหรือไม่?


1

หนึ่งในเหตุผลคือเลขคณิตจุดลอยตัวคือ "ดีพอ" (หรืออย่างน้อยก็เป็นไปได้) มันให้ผลลัพธ์ที่แม่นยำอย่างรวดเร็ว

ตราบใดที่คุณตระหนักถึงข้อ จำกัด ของการคำนวณเลขทศนิยมและเปลี่ยนอัลกอริธึมของคุณเพื่อรับมือกับมัน (ดูคำตอบของ Andrew Russell) จากนั้นคุณจะสร้างโค้ดที่ "ทำงาน"


-1

ฉันกำลังเขียนเกม ในเกม / โปรแกรมของฉันฉันวาดยานอวกาศที่จุดกำเนิดโดยใช้กล้องที่ค่อนข้างคงที่และดาวเคราะห์ของฉันที่ฉันวาดด้วยกล้องแยก และสองสิ่งนี้ดูแลปัญหาให้ฉัน แต่โลกของฉันยังไม่ละเอียดมากนัก สำหรับวิธีการที่แอนดรูว์รัสเซลพูดถึงเกี่ยวกับการเคลื่อนย้ายโลก (และฉันสมมติว่ากล้องและผู้อยู่อาศัยกลับไปสู่จุดกำเนิด) ฉันจะไม่ลองอย่างนั้นถ้าคุณวางแผนที่จะทำให้เกมเป็นเกมบนเครือข่าย หากคุณย้ายโลกในแอปพลิเคชันเซิร์ฟเวอร์ตามการเคลื่อนไหวของลูกค้าแต่ละรายโลกจะต้องดิ้นรนเพื่อตำแหน่ง และจะเข้ารับตำแหน่งตลอดเวลาจากทุกคนที่เล่นซึ่งจะเป็นความผิดพลาดครั้งใหญ่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.