ข้ามไปที่เนื้อหา
บทที่ 3อ่านประมาณ 18 นาที

การแทนค่า Floating-Point ตามมาตรฐาน IEEE 754

เรียนจบบทนี้แล้วจะ

  • อธิบายว่าทำไมต้องใช้ Floating-Point
  • เชื่อม scientific notation ฐานสิบกับรูป 1.xxx × 2ᵉ
  • ระบุ field Sign, Exponent, Fraction ของ Single Precision ได้
  • encode เลขฐานสิบเป็น 32 บิตและ decode กลับได้
หัวข้อในบทนี้

Scientific notation: จากฐานสิบสู่ฐานสอง

นักวิทยาศาสตร์เขียนเลขที่ใหญ่หรือเล็กมากในรูป ตัวเลข 1 หลักหน้าจุด × 10 ยกกำลัง เช่น

1250 = 1.25 × 103 · 0.00042 = 4.2 × 10−4

ฐานสองทำแบบเดียวกันได้ เลื่อนจุดจนหน้าจุดเหลือเลข 1 ตัวเดียว (ในฐานสองหลักแรกที่ไม่ใช่ 0 ต้องเป็น 1 เสมอ) แล้วจดว่าเลื่อนไปกี่ตำแหน่ง ขั้นนี้เรียกว่า

101.112 = 1.01112 × 22

ทำไมต้องมี Floating-Point

ถ้าเก็บจำนวนจริงแบบกำหนดตำแหน่งจุดตายตัว (fixed-point) เช่น 16 บิตหน้าจุด 16 บิตหลังจุด จะเก็บได้แค่ค่าในช่วงแคบ ๆ ค่าใหญ่มาก (ระยะทางระหว่างดาว) หรือเล็กมาก (ขนาดอะตอม) จะเก็บไม่ได้เลย

เก็บแค่ ตัวเลขสำคัญ กับ เลขชี้กำลัง แยกกัน จุดจึง “ลอย” ไปอยู่ตรงไหนก็ได้ตามขนาดของค่า ด้วย 32 บิตเท่าเดิมเก็บได้ตั้งแต่ประมาณ 1 × 10−45 ถึง 3.4028235 × 1038 แลกกับความละเอียดที่มีจำกัด (ราว 7 หลักฐานสิบ)

มาตรฐานที่ทุกเครื่องใช้คือ IEEE 754 ซึ่งกำหนดรูปแบบบิต วิธีปัดเศษ และค่าพิเศษ ทำให้ทุกเครื่องคำนวณได้ผลเหมือนกันทุกบิต

Single Precision: Sign 1 · Exponent 8 · Fraction 23

ใช้ 32 บิต แบ่งเป็น 3 ส่วน (สีของแต่ละส่วนเหมือนกันทุกบทในเว็บนี้):

  • Sign
  • Exponent
  • Fraction
ตัวอย่าง: 5.750x40B80000
S1 บิต
Exponent8 บิต
Fraction23 บิต
  • (1 บิต): 0 = บวก, 1 = ลบ
  • (8 บิต): เลขชี้กำลังของ 2 เก็บแบบบวก Bias
  • (23 บิต): บิตหลังจุดของตัวเลขสำคัญ
ค่า = (−1)Sign × 1.Fraction × 2Exponent − 127

แตะที่บิตใดก็ได้เพื่อดูว่าบิตนั้นอยู่ส่วนไหนและมีน้ำหนักเท่าไร

Exponent และ Bias 127

เลขชี้กำลังจริงมีทั้งบวกและลบ (ค่าเล็กกว่า 1 มีเลขชี้กำลังติดลบ) แต่ field Exponent เก็บเป็นจำนวนเต็มไม่มีเครื่องหมาย 0–255 จึงบวก 127 ก่อนเก็บ ค่าที่เก็บเรียกว่า

Biased exponent = exponent จริง + 127 · exponent จริง = Biased exponent − 127

เช่น exponent จริง 2 เก็บเป็น 2 + 127 = 129 = 10000001 · exponent −3 เก็บเป็น −3 + 127 = 124 = 01111100

ทำไมใช้ Bias แทนบิตเครื่องหมาย

เพราะเมื่อเก็บแบบบวก Bias ค่าบวกที่ใหญ่กว่าจะมีรูปแบบบิตที่เป็นจำนวนเต็มใหญ่กว่าเสมอ ฮาร์ดแวร์จึงเทียบขนาดของ float ได้ด้วยวงจรเทียบจำนวนเต็มธรรมดา

Hidden bit

หลัง Normalize แล้ว หน้าจุดเป็น 1 เสมอ จึงไม่ต้องเก็บ 1 ตัวนี้ เรียกว่า เก็บแค่บิตหลังจุด 23 บิตใน Fraction แต่ได้ความละเอียด 24 บิต ตัวเลข 1.Fraction เต็ม ๆ เรียกว่า

ขั้นตอน encode: ฐานสิบ → 32 บิต

  1. แปลงเป็นฐานสอง (ส่วนเต็มหาร 2 ซ้ำ ส่วนเศษคูณ 2 ซ้ำ)
  2. Normalize ให้อยู่ในรูป 1.xxx × 2ᵉ
  3. กำหนด Sign bit
  4. คำนวณ Biased exponent = e + 127 แล้วเขียนเป็นฐานสอง 8 บิต
  5. เติม Fraction ด้วยบิตหลังจุด 23 บิต (ถ้ามีบิตเกินต้องปัดเศษ)
  6. รวม 3 ส่วนเป็น 32 บิต (มักเขียนเป็น hex 8 หลัก)
ตัวอย่าง: encode 5.75
  1. แปลงเป็นฐานสอง: 5.75 = 101.112
  2. Normalize: 1.0111 × 22 (เลื่อนจุดไปทางซ้าย 2 ตำแหน่ง)
  3. Sign: ค่าบวก → 0
  4. Biased exponent: 2 + 127 = 129 = 10000001
  5. Fraction (บิตหลังจุด เติม 0 จนครบ 23 บิต): 01110000000000000000000
  6. รวม: 0 10000001 01110000000000000000000 = 0x40B80000
5.750x40B80000
S1 บิต
Exponent8 บิต
Fraction23 บิต
ตัวอย่าง: encode -13.25
  1. แปลงเป็นฐานสอง: 13.25 = 1101.012
  2. Normalize: 1.10101 × 23 (เลื่อนจุดไปทางซ้าย 3 ตำแหน่ง)
  3. Sign: ค่าลบ → 1
  4. Biased exponent: 3 + 127 = 130 = 10000010
  5. Fraction (บิตหลังจุด เติม 0 จนครบ 23 บิต): 10101000000000000000000
  6. รวม: 1 10000010 10101000000000000000000 = 0xC1540000
-13.250xC1540000
S1 บิต
Exponent8 บิต
Fraction23 บิต

ขั้นตอน decode: 32 บิต → ฐานสิบ

ทำย้อนกลับ: แยก field → ดูประเภทจาก Exponent → exponent จริง = E − 127 → เติม hidden bit → แทนค่าในสูตร

ตัวอย่าง: decode 0x3E200000
S1 บิต
Exponent8 บิต
Fraction23 บิต
  1. แยก field: Sign 0 · Exponent 01111100 = 124 · Fraction 01000000000000000000000
  2. Exponent 1–254 จึงเป็นค่า Normal · Exponent จริง = 124 − 127 = -3
  3. Significand = hidden bit 1 + Fraction = 1.01
  4. ค่า = (−1)0 × 1.01 × 2−3 = 0.15625

0.1 เก็บไม่พอดี

จากบทที่ 2 เรารู้แล้วว่า 0.1 ในฐานสองซ้ำไม่รู้จบ Single Precision มี Significand แค่ 24 บิต จึงต้องปัดให้ใกล้ที่สุด (round to nearest, ties to even) ผลคือ 0x3DCCCCCD ซึ่งมีค่าจริงเท่ากับ

0.100000001490116119384765625

ต่างจาก 0.1 อยู่ 1.4901161… × 10−9 เล็กมากแต่ไม่ใช่ 0 เวลาโปรแกรมแสดงผลเป็น 0.1 เพราะเลือกทศนิยมที่สั้นที่สุดที่แปลงกลับได้บิตเดิม

จำนวนจริงส่วนใหญ่เก็บแบบพอดีไม่ได้ด้วยบิตจำนวนจำกัด ค่าที่เก็บเป็นแค่ค่าที่ใกล้ที่สุดที่ format นั้นมี

Exponent 0 และ 255 มีความหมายพิเศษ

ExponentFractionความหมาย
00±0 (มีทั้ง +0 และ −0)
0≠ 0: 0.Fraction × 2−126 (ไม่มี hidden bit)
1–254อะไรก็ได้ค่าปกติ (normal) ตามสูตรข้างบน
2550±
255≠ 0
  • ค่าจำกัดที่มากที่สุด: 0x7F7FFFFF ≈ 3.4028235 × 1038
  • ค่า normal ที่เล็กที่สุด: 0x00800000 = 2−126 ≈ 1.1754944 × 10−38
  • ค่า subnormal ที่เล็กที่สุด: 0x00000001 = 2−149 ≈ 1 × 10−45

บทนี้แสดงค่าพิเศษแบบสั้น ๆ ส่วนการคำนวณกับค่าพิเศษอธิบายเต็มในบทที่ 5

IEEE 754 Converter

มี 2 โหมด: พิมพ์เลขฐานสิบเพื่อ encode เป็น 32 บิต หรือกด/พิมพ์บิตเพื่อ decode กลับเป็นฐานสิบ แต่ละโหมดดูได้ทีละขั้นด้วยปุ่มด้านล่าง ในขั้น Normalize ลองกดปุ่มเลื่อนจุดเองก่อนดูคำตอบ

ผลลัพธ์ของ 5.750x40B80000
S1 บิต
Exponent8 บิต
Fraction23 บิต

เก็บได้พอดี ไม่ต้องปัดเศษ

  • Sign
  • Exponent
  • Fraction
  • Hidden bit
  • Guard / Round / Sticky

1/7ส่วนจำนวนเต็มเป็นฐานสอง

ขั้นที่ 1 จาก 7: ส่วนจำนวนเต็มเป็นฐานสอง

หารด้วย 2ได้เศษ (บิต)
5 ÷ 221
2 ÷ 210
1 ÷ 201

อ่านเศษจากล่างขึ้นบน: 1012

หารด้วย 2 ไปเรื่อย ๆ จนได้ 0 เศษของแต่ละรอบคือบิต เริ่มจากบิตขวาสุด (น้ำหนัก 2⁰)

ขั้นที่ 1/7

ข้อจำกัด: เครื่องมือนี้ใช้ Single Precision (32 บิต) และปัดแบบ round to nearest, ties to even เท่านั้น · รับทศนิยม, scientific notation (เช่น 1.5e-7), inf และ nan · ไม่เกิน 200 ตัวอักษร

สรุปท้ายบท

  • Scientific notation เขียนค่าเป็นตัวเลขสำคัญ × ฐานยกกำลัง ฐานสองเขียนเป็น 1.xxx × 2ᵉ (Normalize)
  • Single Precision มี 32 บิต: Sign 1 บิต · Exponent 8 บิต · Fraction 23 บิต
  • Exponent เก็บแบบบวก Bias 127 (Biased exponent = e + 127) และค่า normal มี hidden bit = 1 ที่ไม่ต้องเก็บ
  • encode: ฐานสอง → Normalize → Sign → e + 127 → Fraction 23 บิต (ปัดถ้าเกิน) → รวม 32 บิต · decode ทำย้อนกลับ
  • Exponent 0 ใช้กับ ±0 และ Subnormal · Exponent 255 ใช้กับ ±∞ และ NaN
  • ด้วยบิตจำกัด ค่าส่วนใหญ่ (เช่น 0.1) เก็บได้แค่ค่าที่ใกล้ที่สุด จึงมีความคลาดเคลื่อนเล็ก ๆ เสมอ