ซึ่งเป็นจำนวนเต็มแรกที่ IEEE 754 float ไม่สามารถแสดงได้อย่างแน่นอน


162

เพื่อความชัดเจนถ้าฉันใช้ภาษาที่ใช้ IEE 754 ลอยและฉันประกาศ:

float f0 = 0.f;
float f1 = 1.f;

... แล้วพิมพ์มันออกมาฉันจะได้ 0.0000 และ 1.0000 - แน่นอน

แต่ IEEE 754 ไม่สามารถแสดงตัวเลขทั้งหมดตามเส้นจริงได้ ใกล้กับศูนย์ 'ช่องว่าง' มีขนาดเล็ก เมื่อคุณห่างออกไปช่องว่างก็ใหญ่ขึ้น

ดังนั้นคำถามของฉันคือ: สำหรับ IEEE 754 float ซึ่งเป็นจำนวนเต็ม (ใกล้เคียงที่สุดเป็นศูนย์) ซึ่งไม่สามารถแสดงได้อย่างแน่นอน ตอนนี้ฉันแค่กังวลกับ 32- บิตลอยแม้ว่าฉันจะสนใจฟังคำตอบสำหรับ 64- บิตถ้ามีคนให้!

ฉันคิดว่ามันจะง่ายเหมือนการคำนวณ 2 bits_of_mantissaและการเพิ่ม 1 โดยที่bits_of_mantissaคือจำนวนบิตมาตรฐานที่เปิดเผย ฉันทำสิ่งนี้สำหรับ 32- บิตลอยบนเครื่องของฉัน (MSVC ++, Win64) และมันก็ดูเหมือนดี


ทำไมคุณถึงเพิ่มถ้าคุณต้องการหมายเลขที่ไม่สามารถอธิบายได้ และคุณใช้หรือรับหมายเลขอะไร และการบ้านนี้คืออะไร และชื่อคำถามของคุณบอกว่า "จำนวนเต็ม" แต่คำถามของคุณบอกว่า "ลอย"
msw

5
เพราะฉันคิดว่าการเพิ่มแม็นทีสสาจะทำให้ฉันมีจำนวนที่แทนได้สูงสุด 2 ^ 22 ไม่มันเป็นคำถามที่อยากรู้อยากเห็น ฉันมักจะรู้สึกผิดที่ใส่ ints ในทุ่นแม้ว่าฉันจะรู้ว่า int ในคำถามนั้นจะเล็กมากเสมอ ฉันต้องการรู้ว่าขีด จำกัด บนคืออะไร เท่าที่ฉันสามารถบอกได้หัวข้อและคำถามเหมือนกันเพียงแค่ใช้ถ้อยคำต่างกัน
Floomi


1
ทำซ้ำกับstackoverflow.com/questions/1848700/… ?
FrankH

1
@KyleStrand เปลี่ยนกลับ ^ 2 ฉันไม่รู้ว่าทำไมคนเราถึงถูกต้องมากกว่าคนอื่นในเวลา ตอนนี้พวกเขาทั้งคู่ดูประหม่าเมื่อเทียบกับ“ …คือจำนวนบิต…”
Pascal Cuoq

คำตอบ:


211

2 mantissa bits + 1 + 1

+1 ในเลขชี้กำลัง (mantissa บิต ​​+ 1) เป็นเพราะถ้า mantissa มีabcdef...ตัวเลขที่แสดงถึงเป็นจริง1.abcdef... × 2^eให้ความแม่นยำบิตโดยนัยเพิ่มเติม

ดังนั้นจำนวนเต็มแรกที่ไม่สามารถแสดงได้อย่างถูกต้องและจะถูกปัดเศษคือ:
สำหรับfloat, 16,777,217 (2 24 + 1)
สำหรับdouble9,007,199,254,740,993 (2 53 + 1)

>>> 9007199254740993.0
9007199254740992

ฉันประกาศfloatและตั้งค่าเท่ากับ 16,777,217 แต่เมื่อฉันพิมพ์โดยใช้coutมันส่งผลให้ 16,777,216 C++ฉันใช้ ทำไมฉันถึงได้ 16,777,217 ไม่ได้?
sodiumnitrate

18
@sodiumnitrate ตรวจสอบชื่อคำถาม 16777217 เป็นจำนวนเต็มแรกที่ไม่สามารถแสดงได้อย่างแน่นอน
kennytm

โอเคขอบคุณ. ฉันสับสนแล้วขอโทษด้วย ฉันมีคำถามอีกข้อว่าหลังจาก 16777216 แล้วเลขต่อไปควรเป็น 2 * 16777216 หรือไม่? เมื่อฉันเรียกใช้โปรแกรมที่คล้ายกันฉันจะได้รับ 16777218 โดยเพิ่ม 2 ถึง 16777126
sodiumnitrate

5
เลขจำนวนเต็มถัดไปคือ 16777218 เพราะตอนนี้ 2 กลายเป็นเลขฐานสองที่สำคัญสุดท้าย
kennytm

6
ใน C ++, ว่า(1 << std::numeric_limits<float>::digits) + 1และใน (1 << FLT_MANT_DIG) + 1C, ตัวก่อนหน้านี้ดีเพราะสามารถเป็นส่วนหนึ่งของเทมเพลตได้ อย่าเพิ่ม +1 หากคุณต้องการจำนวนเต็มที่เป็นตัวแทนที่ใหญ่ที่สุด
Henry Schreiner

38

ค่าที่ใหญ่ที่สุดที่สามารถแทนได้ด้วยจำนวนเต็มnบิตคือ 2 n -1 ตามที่ระบุไว้ข้างต้น a floatมีความแม่นยำ 24 บิตในซิกนิฟิแคนด์ซึ่งดูเหมือนว่าแปลว่า 2 24จะไม่พอดี อย่างไรก็ตาม



พลังของ 2 ภายในขอบเขตของเลขชี้กำลังมีค่าเท่ากับ 1.0 × 2 nดังนั้น 2 24 จึงสามารถพอดีได้ดังนั้นจำนวนเต็มที่ไม่สามารถแทนได้แรกfloatคือ 2 24 +1 ตามที่ระบุไว้ข้างต้น อีกครั้ง


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