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

การคูณและการหารเลข Floating-Point

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

  • อธิบายได้ว่าทำไมคูณ/หารไม่ต้องปรับ Exponent ให้เท่ากันแต่ต้องแก้ Bias
  • หา Sign ด้วย XOR และคำนวณ Biased Exponent ของผลคูณและผลหาร
  • คูณ Significand แบบ shift-and-add และหารแบบหารยาวฐานสอง
  • Normalize และปัดเศษด้วย Guard, Round, Sticky
  • รู้จัก Overflow, Underflow, การหารด้วยศูนย์ และ NaN
หัวข้อในบทนี้

ต่างจากการบวก/ลบอย่างไร

คูณเลขแบบ scientific notation ง่ายกว่าบวก: (2 × 10³) × (3 × 10⁴) = 6 × 10⁷ คือคูณตัวเลขสำคัญ แล้ว บวก เลขชี้กำลัง ไม่ต้องปรับเลขชี้กำลังให้เท่ากันก่อน ส่วนการหารก็หารตัวเลขสำคัญแล้ว ลบ เลขชี้กำลัง

บวก/ลบ (บทที่ 4)คูณ/หาร (บทที่ 5)
ปรับ Exponent ให้เท่ากันต้องทำ (เลื่อนตัวที่ Exponent น้อยกว่า)ไม่ต้องทำ
Exponent ของผลใช้ตัวที่มากกว่าEA + EB − 127 หรือ EA − EB + 127
Signขึ้นกับขนาดและการดำเนินการSA XOR SB
Significandบวกหรือลบคูณหรือหาร
Normalizeขวา 1 บิต (มีตัวทด) หรือซ้ายหลายบิต (ลบกันแล้วค่าหาย)คูณ: ขวาไม่เกิน 1 บิต · หาร: ซ้ายไม่เกิน 1 บิต
ปัดเศษGuard, Round, StickyGuard, Round, Sticky (หาร: Sticky ได้จากเศษด้วย)

การคูณ 8 ขั้น

  1. แยกทั้งสองค่าเป็น Sign, Biased exponent และ Significand (1.Fraction)
  2. Sign: S = SA XOR SB
  3. Exponent: E = EA + EB − 127
  4. คูณ Significand 24 บิตสองค่าแบบ shift-and-add ผลแม่นยำยาวได้ถึง 48 บิต และอยู่ในช่วง [1, 4)
  5. Normalize: ถ้าผลคูณ ≥ 2 เลื่อนขวา 1 บิตแล้ว Exponent + 1
  6. ปัดให้เหลือ 24 บิตด้วย Guard, Round, Sticky ถ้าปัดแล้วมีตัวทดให้ Normalize อีกครั้ง
  7. ตรวจช่วง: Overflow ได้ ±∞ · Underflow ได้ Subnormal หรือ ±0
  8. encode ผลเป็น 32 บิต

ทำไมลบ Bias หนึ่งครั้ง

Biased exponent แต่ละตัวมี +127 อยู่แล้ว: EA = eA + 127 และ EB = eB + 127 ถ้าบวกกันตรง ๆ จะได้ eA + eB + 254 ซึ่งมี Bias ซ้ำสองครั้ง จึงต้องลบ 127 ออกหนึ่งครั้งให้เหลือ (eA + eB) + 127

E = EA + EB − 127 · Significand ∈ [1, 2) × [1, 2) = [1, 4)

การคูณแบบ shift-and-add: ทุกบิต 1 ของตัวคูณ () ให้ หนึ่งแถว คือตัวตั้งเลื่อนไปตามตำแหน่งของบิตนั้น แล้วบวกทุกแถว

ตัวอย่าง M3 แบบละเอียด: 6.5 × 2.75

ตัวอย่าง M3 แบบละเอียด: 6.5 × 2.75
  1. 6.5 = 0 10000001 10100000000000000000000 → Significand 1.101, Biased exponent 129
    2.75 = 0 10000000 01100000000000000000000 → Significand 1.011, Biased exponent 128
  2. Sign: 0 XOR 0 = 0
  3. Exponent: 129 + 128 − 127 = 130
  4. Significand: ตัวคูณ 1.011 มีบิต 1 อยู่ 3 ตัว จึงมี partial product 3 แถว
       1.101000
    +  0.011010
    +  0.001101
    = 10.001111
  5. Normalize: ผล ≥ 2 เลื่อนขวา 1 บิต Exponent 130 + 1 = 131
  6. ปัดเศษ: G = 0, R = 0, S = 0 → ไม่ต้องปัด
  7. ผลลัพธ์: 0 10000011 00011110000000000000000 = 0x418F0000 = 17.875

การหาร 8 ขั้น

  1. แยกทั้งสองค่าเป็น Sign, Biased exponent และ Significand
  2. Sign: S = SA XOR SB
  3. Exponent: E = EA − EB + 127
  4. หาร Significand ของตัวตั้งด้วยตัวหารด้วยการหารยาวฐานสอง ผลหารอยู่ในช่วง (0.5, 2) หาบิตให้พอสำหรับ Guard และ Round ส่วน Sticky เป็น 1 เมื่อเศษสุดท้ายไม่เป็นศูนย์
  5. Normalize: ถ้าผลหาร < 1 เลื่อนซ้าย 1 บิตแล้ว Exponent − 1
  6. ปัดเศษ แล้ว Normalize อีกครั้งถ้ามีตัวทด
  7. ตรวจช่วง (Overflow หรือ Underflow)
  8. encode ผลเป็น 32 บิต

ทำไมบวก Bias กลับหนึ่งครั้ง

EA − EB = (eA + 127) − (eB + 127) = eA − eB · Bias หักล้างกันหายไปหมด จึงต้องบวก 127 กลับหนึ่งครั้ง

การหารยาวฐานสองง่ายกว่าฐานสิบ เพราะแต่ละรอบมีแค่ 2 ทาง: ถ้าเศษ ≥ ให้ลบแล้วได้บิตผลหาร 1 ไม่งั้นได้ 0 แล้วเลื่อนเศษไปทางซ้าย 1 บิต

ตัวอย่าง D3 แบบละเอียด: 1 ÷ 3

ตัวอย่าง D3 แบบละเอียด: 1 ÷ 3
  1. 1 = 0 01111111 00000000000000000000000 → Significand 1.0, Biased exponent 127
    3 = 0 10000000 10000000000000000000000 → Significand 1.1, Biased exponent 128
  2. Sign: 0 XOR 0 = 0
  3. Exponent: 127 − 128 + 127 = 126
  4. Significand: 1.0 ÷ 1.1 ด้วยการหารยาว 27 รอบ ได้ผลหาร 0.10101010101010101010101010 เศษสุดท้าย ≠ 0 (ไม่มีวันเป็น 0)
  5. Normalize: ผล < 1 เลื่อนซ้าย 1 บิต Exponent 126 − 1 = 125
  6. ปัดเศษ: G = 1, R = 0, S = 1 (S มาจากเศษที่ไม่เป็นศูนย์) → ปัดขึ้น
  7. ผลลัพธ์: 0 01111101 01010101010101010101011 = 0x3EAAAAAB = 0.33333334 (ค่าที่เก็บจริง 0.3333333432674407958984375)

กรณีพิเศษและ IEEE exception

กรณีเหล่านี้ไม่ต้องไล่ทุกขั้น ใช้กฎสั้น ๆ ได้ผลทันที และ IEEE 754 ไม่ได้หยุดโปรแกรม แต่ให้ค่าพิเศษพร้อมแจ้ง exception

กรณีผลลัพธ์Exception
x ÷ 0 (x เป็นค่าจำกัดที่ไม่ใช่ 0)±∞ (Sign = XOR)Division by zero
0 ÷ 0, ∞ ÷ ∞, 0 × ∞NaNInvalid operation
0 × x, 0 ÷ x (x เป็นค่าจำกัดที่ไม่ใช่ 0)±0 (Sign = XOR)—
x ÷ ∞ (x เป็นค่าจำกัด)±0—
∞ × x (x ไม่ใช่ 0), ∞ ÷ x (x เป็นค่าจำกัด)±∞—
มีตัวใดตัวหนึ่งเป็น NaNNaN—
ผลใหญ่กว่าค่าจำกัดที่มากที่สุด±∞Overflow (และ Inexact)
ผลเล็กกว่าค่า normalized ที่เล็กที่สุดSubnormal หรือ ±0Underflow (เมื่อปัดแล้วไม่ตรง)

และ ดูได้ในขั้น “ตรวจ Overflow / Underflow” ของ Simulator ลองตัวอย่าง M5, M6, D4, D5 หรือปุ่มค่าพิเศษ

ข้อผิดพลาดที่เจอบ่อย

  • ลืมลบ Bias ตอนคูณ (ได้ EA + EB เฉย ๆ) หรือลืมบวก Bias กลับตอนหาร → Exponent ผิดไป 127
  • ลืม hidden bit คูณ/หารแค่ Fraction 23 บิตโดยไม่มีเลข 1 หน้าจุด → ผลผิดทั้งหมด
  • ใส่ Sign ผิด คูณ/หารใช้ XOR เสมอ ไม่ได้ขึ้นกับว่าค่าไหนใหญ่กว่า
  • Normalize ผิดทาง คูณเลื่อนขวา (ผลอาจถึง 2 ขึ้นไป) หารเลื่อนซ้าย (ผลอาจต่ำกว่า 1)
  • ทิ้งเศษของการหาร เศษที่ไม่เป็น 0 ต้องกลายเป็น Sticky = 1 ไม่งั้นปัดผิดได้

แบบจำลองเพื่อการเรียนรู้

ขั้นตอนนี้เป็นแบบจำลองของขั้นหลักเพื่อการเรียนรู้ ไม่ใช่วงจรคูณหรือหารของฮาร์ดแวร์รุ่นใดรุ่นหนึ่ง (เช่น array multiplier, Booth encoding, SRT division) แต่ผลลัพธ์ตรงกับ IEEE 754 ทุกบิต

ตัวอย่าง M1–M6 และ D1–D5

M11.5 × 2.5= 0x40700000 = 3.75ขั้นตอนพื้นฐาน ผลคูณน้อยกว่า 2 จึงไม่ต้อง Normalize
M20.5 × -0.4375= 0xBE600000 = −0.21875Sign ได้จาก XOR และต้องลบ Bias ออกหนึ่งครั้ง
M36.5 × 2.75= 0x418F0000 = 17.875partial product 3 แถว ผลคูณ ≥ 2 จึงเลื่อนขวาและ Exponent + 1
M40.1 × 3= 0x3E99999A = 0.3บิตที่ตัดทิ้งเกินครึ่ง จึงปัดขึ้น
M53e38 × 10= 0x7F800000 = +∞Exponent เกิน 254 จึง Overflow เป็น +∞
M61e-30 × 1e-30= 0x00000000 = 0ผลเล็กเกินกว่าที่เก็บได้ จึง Underflow เป็น 0
D17.5 ÷ 2.5= 0x40400000 = 3ขั้นตอนพื้นฐาน ผลหาร ≥ 1 หารลงตัว
D29 ÷ 12= 0x3F400000 = 0.75ผลหารน้อยกว่า 1 จึงเลื่อนซ้ายและ Exponent − 1
D31 ÷ 3= 0x3EAAAAAB = 0.33333334หารไม่ลงตัว เศษที่เหลือกลายเป็น Sticky แล้วปัดขึ้น
D41 ÷ 0= 0x7F800000 = +∞หารด้วยศูนย์ ได้ +∞
D50 ÷ 0= 0x7FC00000 = NaNไม่มีความหมายทางคณิตศาสตร์ ได้ NaN

Simulator: คูณและหาร

เลือก × หรือ ÷ แล้วดูทีละขั้น: XOR ของ Sign, การแก้ Bias (ฐานสิบและฐานสอง 8 บิต), partial product ทีละแถว, การหารยาวทีละแถว, Normalize, ปัดเศษ, ตรวจช่วง และผลลัพธ์ · ใส่ค่าพิเศษ 0, −0, ∞, −∞, NaN ได้จากปุ่มด้านล่างช่องกรอก

พิมพ์ทศนิยมหรือ scientific notation เช่น 0.1, -6.5, 1e-8 หรือ inf, nan · ใช้จุดเป็นจุดทศนิยม

ตัวอย่าง

ค่าพิเศษ ใส่ที่
A = 6.50x40D00000
S1 บิต
Exponent8 บิต
Fraction23 บิต
B = 2.750x40300000
S1 บิต
Exponent8 บิต
Fraction23 บิต
  • Sign
  • Exponent
  • Fraction
  • Hidden bit
  • Guard / Round / Sticky

1/9แยกส่วนของ A

ขั้นที่ 1 จาก 9: แยกส่วนของ A

ตัวถูกดำเนินการ A0x40D00000
S1 บิต
Exponent8 บิต
Fraction23 บิต

ประเภท: Normal · ค่าที่เก็บจริง: 6.5

Sign = 0 · Biased exponent = 129 (Exponent จริง 2)

Significand = 1.101

ขั้นที่ 1/9

ผลลัพธ์ 6.5 × 2.75

ผลแม่นยำของค่าที่พิมพ์
17.875
ผลแม่นยำของค่าที่เก็บจริงใน float
17.875
ผล float (binary32)
17.8750x418F0000เก็บจริง: 17.875

ผลต่างจากค่าที่พิมพ์: 0 (ตรงพอดี)

สรุปท้ายบท

  • Sign ของผลคูณและผลหาร = SA XOR SB เสมอ
  • คูณ: E = EA + EB − 127 (ลบ Bias ที่ซ้ำ) · หาร: E = EA − EB + 127 (บวก Bias ที่หายไปกลับ)
  • คูณ/หาร Significand ที่รวม hidden bit แล้ว: คูณแบบ shift-and-add (ผลใน [1, 4)) · หารแบบหารยาว (ผลใน (0.5, 2))
  • Normalize: คูณเลื่อนขวาไม่เกิน 1 บิต · หารเลื่อนซ้ายไม่เกิน 1 บิต
  • ปัดเศษด้วย Guard, Round, Sticky (round to nearest, ties to even) การหารเอาเศษที่ไม่เป็น 0 มาเป็น Sticky
  • กรณีพิเศษ: x ÷ 0 = ±∞ · 0 ÷ 0, ∞ ÷ ∞, 0 × ∞ = NaN · ผลใหญ่เกินเป็น ±∞ (Overflow) · ผลเล็กเกินเป็น Subnormal หรือ ±0 (Underflow)