Lua จัดการกับทั้งจำนวนเต็มและจำนวนลอยได้อย่างไร


11

เท่าที่ฉันจำได้ว่าตัวเองเขียนโปรแกรมฉันได้รับการสอนไม่ให้เปรียบเทียบจำนวนจุดลอยตัวเพื่อความเท่าเทียมกัน ตอนนี้ในขณะที่อ่านการเขียนโปรแกรมใน Luaเกี่ยวกับnumberประเภทLua ฉันพบต่อไปนี้:

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

เป็นจริงสำหรับทุกภาษาหรือไม่ โดยพื้นฐานถ้าเราไม่ไปเกินจุดลอยเป็นสองเท่าเราจะปลอดภัยในเลขคณิตจำนวนเต็มหรือไม่ หรือเพื่อให้สอดคล้องกับชื่อคำถามมีอะไรพิเศษที่ Lua ทำกับnumberประเภทของมันดังนั้นมันจึงทำงานได้ดีทั้งแบบจำนวนเต็มและจุดลอยตัว?



@ JoonasPulakka ขอบคุณนั่นเป็นสิ่งที่มีคุณค่ามาก
Petr Abdulin

คำตอบ:


11

Lua อ้างว่าตัวเลขจุดลอยตัวสามารถแทนตัวเลขจำนวนเต็มเหมือนกับประเภทจำนวนเต็มสามารถทำได้และฉันก็เห็นด้วย ไม่มีการนำเสนอส่วนที่เป็นเศษส่วนที่ไม่แม่นยำในการจัดการ ไม่ว่าคุณจะเก็บจำนวนเต็มในประเภทจำนวนเต็มหรือเก็บไว้ในแมนทิสซาของตัวเลขจุดลอยตัวผลลัพธ์จะเหมือนกัน: จำนวนเต็มนั้นสามารถแสดงได้อย่างแน่นอนตราบใดที่คุณไม่เกินจำนวนบิตในแมนทิสซา , + 1 บิตในเลขยกกำลัง

แน่นอนถ้าคุณพยายามเก็บหมายเลข floating-point ที่แท้จริง (เช่น 12.345) ในการแสดงทศนิยมการเดิมพันทั้งหมดจะปิดดังนั้นโปรแกรมของคุณจะต้องชัดเจนว่าตัวเลขนั้นเป็นจำนวนเต็มจริง ๆ ที่ไม่ล้น mantissa เพื่อที่จะปฏิบัติต่อมันเหมือนเป็นจำนวนเต็มจริง (เช่นเทียบกับการเปรียบเทียบความเท่าเทียมกัน)

หากคุณต้องการความแม่นยำจำนวนเต็มมากกว่านั้นคุณสามารถใช้ไลบรารีความแม่นยำโดยพลการได้ตลอดเวลา

อ่านเพิ่มเติม
ค่าสูงสุดของตัวเลขใน Lua คืออะไร


สิ่งที่เกี่ยวกับการโต้แย้งที่สองของพวกเขาคือจุดลอยตัวนั้นเร็วหรือเร็วกว่าเลขคณิตจำนวนเต็มใน CPUs สมัยใหม่ ฟังดูน่าสงสัยสำหรับฉันแม้ว่าจะใช้เลขทศนิยมในการคำนวณเลขจำนวนเต็มก็ตาม
Andres F.

2
@AndresF ฉันไม่เห็นวิธีที่เร็วขึ้นเว้นแต่คุณจะกำจัดนักแสดงโดยใช้ประเภทตัวเลขเดียวแทนที่จะเป็นสองแบบ
Robert Harvey

ตกลง ไม่สมเหตุสมผลสำหรับฉัน ฉันสงสัยว่ามันถูกเอาออกไปจากบริบทหรือไม่
Andres F.

1
จำนวนเต็มขนาดใหญ่อย่างเพียงพอไม่สามารถเก็บไว้ในวัตถุที่เป็นทศนิยม 64- บิตdoubleมีบิตแมนทิสสาประมาณ 51 บิต; จำนวนเต็มแปลก ๆ ที่ใหญ่กว่าประมาณ 2 ** 51 จะมีข้อผิดพลาดในการปัดเศษ เลขจำนวนเต็ม 64- บิตสามารถเก็บค่าจำนวนเต็มขนาดใหญ่ได้อย่างถูกต้องเนื่องจากไม่ได้อุทิศบิตใด ๆ ให้กับเลขชี้กำลัง
Keith Thompson

@ KeithThompson: ฉันคิดว่ามันมีนัยในคำตอบของฉันเมื่อฉันพูดว่า "เก็บไว้ในแมนทิสซา" อย่างไรก็ตามฉันจะแก้ไขคำตอบเพื่อชี้แจง
Robert Harvey

6

คู่จะถูกเก็บไว้เป็นแมนทิสซาและเลขชี้กำลัง ดูรูปแบบสำหรับข้อมูลเพิ่มเติม โดยทั่วไปตัวเลขทั้งหมดเป็นของรูปแบบ: mantissa * 2 ยกกำลัง สำหรับจำนวนเต็มใด ๆ ที่น้อยกว่า 2 52เลขชี้กำลังจะเป็นศูนย์ทำให้ mantissa bit-for-bit เทียบเท่ากับจำนวนเต็ม 52 บิตที่ไม่ได้ลงชื่อ บิตเครื่องหมายแยกถูกใช้เพื่อระบุจำนวนลบ

ในความเป็นจริงแม้บางจำนวนเต็มขนาดใหญ่กว่า 2 52สามารถแสดงว่าตราบใดที่ทุกตัวเลขที่ผ่านมา 52 ครั้งมีเลขศูนย์ นอกจากนี้เศษส่วนบางอย่างเช่น 0.5 สามารถแสดงได้อย่างแม่นยำ มันก็ต่อเมื่อเศษส่วนมีการทำซ้ำอย่างต่อเนื่อง (เช่น 1/3) ในฐาน 2 หรือมิฉะนั้นต้องใช้บิตมากเกินไปผ่านจุด radix ที่คุณสูญเสียความแม่นยำ


ไม่ใช่เพราะทศนิยมซ้ำอย่างต่อเนื่อง เป็นเพราะตัวเลขฐานสิบ (ฐานสิบ) ไม่สามารถแสดงอย่างชัดเจนว่าเป็นกำลังสอง
Robert Harvey

3
ในฐาน 2 ตัวเลขที่ไม่สามารถแสดงได้อย่างแม่นยำจะเป็นการทำซ้ำอย่างต่อเนื่อง ตัวอย่างเช่นทศนิยม 0.1 กลายเป็น 0.0 (0011) ในรูปแบบไบนารีโดยที่ 0011 ซ้ำอย่างต่อเนื่อง
Karl Bielefeldt

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