วันจันทร์ที่ 26 พฤศจิกายน พ.ศ. 2561

เมื่อ 1 ไม่เท่ากับ 0.1 x 10 (การทำวิทยานิพนธ์ภาคปฏิบัติ ตอนที่ ๙๓) MO Memoir : Monday 26 November 2561

ผมได้สัมผัสกับคอมพิวเตอร์ครั้งแรกก็ตอนเรียนแลปฟิสิกส์ปี ๑ เมื่อปี ๒๕๒๗ เป็นเครื่องไมโครคอมพิวเตอร์ 8 บิท ได้เรียนภาษา BASIC แบบไม่รู้เรื่องรู้ราวอะไรเลย (อันที่จริงยังไม่รู้ด้วยซ้ำว่าคอมพิวเตอร์คืออะไร) จากนั้นในเทอมปลายจึงได้เรียนเขียนภาษา FORTRAN ตัวที่เรียกว่า WATFIVที่เป็นตัวที่มหาวิทยาลัย Waterloo พัฒนาขึ้นมา ตัวนี้เป็นตัวก้ำกึ่งระหว่าง FORTRAN IV (ตัวนี้มาก่อน FORTRAN 66 อีก) และ FORTRAN 77 (มาตรฐานปีค.ศ. ๑๙๗๗) ปีนั้นเรียกว่าโชคดีกว่ารุ่นพี่ตรงที่ เป็นปีแรกที่สามารถพิมพ์โปรแกรมผ่านทางเทอร์มินอลได้แล้ว ไม่ต้องใช้บัตรเจาะรู (บัตรกระดาษแข็ง ๑ บัตรต่อ ๑ บรรทัด ที่ต้องเจาะรูแล้วไปให้เครื่องอ่านบัตรอ่านอีกที)
 
พอถึงปี ๔ ก่อนจบต้องเรียนวิชา Plant Design (ออกแบบโรงงานนะ ไม่ใช่ออกแบบพืช) กัน ตอนนั้นมี IBM PC มาให้ใช้งานกันแล้ว แต่ยังต้องนั่งเขียนโปรแกรมภาษา BASIC เพื่อทำการคำนวณทุกอย่าง (ไม่มีซอร์ฟแวร์สำเร็จรูปให้ใช้เหมือนทุกวันนี้) ระหว่างการคำนวณก็ได้เห็นพฤติกรรมแปลก ๆ ของผลการคำนวณ เช่นถ้าให้คำนวณ n = n + 1 โดยให้ n เริ่มต้นจาก 0 ก็พบว่าพอคำนวณไปได้สักพักคำตอบที่ได้มันกลับไม่ได้เป็นเลขจำนวนเต็ม มันดันมีจุดทศนิยมโผล่ออกมา แต่ตอนนั้นก็ไม่รู้ว่ามันเกิดจากอะไร และไม่รู้ด้วยว่าจะไปหาคำอธิบายจากใครได้
 
ตอนเรียนเขียน FORTRAN นั้นก็เรียนรู้กันว่า สำหรับบางคำสั่ง (เช่นคำสั่งนับการวน loop) ต้องมีการกำหนดค่าตัวแปรให้เป็นชนิด "จำนวนเต็ม" หรือ "Integer" ห้ามกำหนดเป็น "จำนวนจริง" หรือ "Real" ซึ่งก็ไม่รู้เหมือนกันว่าทำไมต้องทำอย่างนั้น และยังไม่รู้ด้วยว่าคำสั่ง "Double precision" นั้นมีเอาไว้ทำไม
 
ข้อสงสัยต่าง ๆ สมัยเรียนนั้นคงจะลืมไปหมด ถ้าไม่ใช่เป็นเพราะตอนไปเรียนโทที่ต่างประเทศได้ทำงานวิจัยที่ต้องเขียนภาษา FORTRAN แล้วอาจารย์ที่ปรึกษาแนะนำให้ไปลงเรียนวิชาพื้นฐานการคำนวณเชิงตัวเลข (การแก้โจทย์สมการคณิตศาสตร์ด้วยวิธีการคำนวณเชิงตัวเลข) ตอนนั้นเองถึงได้เข้าใจว่าบนคอมพิวเตอร์นั้น "จำนวนเต็ม" ต่างกับ "จำนวนจริง" อย่างไร และมันเกิดอะไรขึ้นเมื่อเราเอาเลขฐาน 10 (ซึ่งเป็นตัวเลขที่เราใช้กันในชีวิตประจำวัน) ไปให้คอมพิวเตอร์คำนวณด้วยระบบเลขฐาน 2 ที่มันเข้าใจ
 
เนื้อหาในบทความชุดนี้เป็นการนำเอาสิ่งที่เขียนไว้สำหรับสอนนิสิตวิศวกรรมเคมีปี ๓ ในเรื่องพื้นฐานการคำนวณเชิงตัวเลขใน "บทที่ ๑ การคำนวณในระบบเลขทศนิยม" ซึ่งอันที่จริงก็มีไฟล์ pdf ไว้ให้ดาวน์โหลดฟรีบนหน้า blog อยู่แล้ว เพียงแต่รูปแบบไฟล์ pdf คงทำให้การค้นหาโดยใช้คำสำคัญค้นหาด้วย google นั้นทำให้มันหาไม่เจอ ก็เลยนำมาเขียนเป็น text ไว้บนหน้า blog หน่อย เพราะช่วงสัปดาห์ที่ผ่านมาเห็นมีการกดแชร์บางบทความกัน เลยทำให้รู้ว่าเรื่อง "ความรู้พื้นฐาน" นี้ยังมีคนไม่รู้อยู่มาก แม้ว่าจะเป็นงานในสายวิชาชีพตัวเอง โดยในบทความชุดนี้จะขอเริ่มจากคำถามง่าย ๆ ข้างล่างก่อน

คำถาม ถ้าต้องการคำนวณค่า (1 + 1) บนคอมพิวเตอร์ โดยคำนวณในรูปแบบ
) จำนวนเต็ม ค่าของตัวเลขแต่ละตัวจะถูกบันทึกไว้ในรูปแบบ 1
ดังนั้นค่าที่ได้จากการคำนวณ (1 + 1) = ...............
) จำนวนจริง ค่าของตัวเลขแต่ละตัวจะถูกบันทึกไว้ในรูปแบบ 0.1 x 10
ดังนั้นค่าที่ได้จากการคำนวณ (0.1 x 10 + 0.1 x 10) = ..............
เมื่อทำการคำนวณ ผลลัพธ์ที่ได้จะออกมาเหมือนกันหรือไม่
ในชีวิตประจำวันของเรานั้นเราใช้เลขฐาน 10 (decimal digit) เป็นหลักในการติดต่อสื่อสารและการคำนวณต่าง ๆ ตัวเลขฐาน 10 ที่ใช้มีตั้งแต่ 0 ถึง 9 ค่าของเลขฐาน 10 แต่ละจำนวนขึ้นอยู่กับค่าประจำหลักดังแสดงในตารางที่ ๑ 
 


ตารางที่ ค่าประจำหลักของเลขฐาน 10

หลักที่
5
4
3
2
1
จุดทศนิยม
1
2
3
4
5
ค่าประจำหลัก
104
103
102
101
100
.
10-1
10-2
10-3
10-4
10-5



ระบบเลขฐาน 2 (binary digit) เป็นระบบการคำนวณที่ใช้กันในเครื่องคอมพิวเตอร์แบบดิจิตอล (digital computer) ทั่วไป เลขที่ใช้จะมีเพียงแค่ 0 กับ 1 ค่าของเลขฐาน 2 แต่ละจำนวนขึ้นอยู่กับค่าประจำหลักดังแสดงในตารางที่ ๒ ข้างล่าง



ตารางที่ ๒ ค่าประจำหลักของเลขฐาน 2

หลักที่
5
4
3
2
1
จุดทศนิยม
1
2
3
4
5
ค่าประจำหลัก
24
23
22
21
20
.
2-1
2-2
2-3
2-4
2-5



ในการแปลงเลขฐานสิบให้เป็นเลขฐานสอง เราทำได้โดยการนำตัวเลขที่อยู่ในแต่ละหลักคูณเข้ากับค่าประจำหลัก แล้วทำการบวกเข้าด้วยกัน ดังเช่นในกรณีของเลขฐานสิบที่เป็นจำนวนเต็มในตารางที่ ๓



ตารางที่ ๓ ตัวอย่างตัวเลขฐาน 10 ที่เป็นจำนวนเต็มและตัวเลขฐาน 2 ที่เทียบเท่ากัน


เลขฐาน 10
เลขฐานสอง
18
10010
100
1100100
10000
10011100010000
152431
100101101101101111
10000000
100110001001011010000011



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

ต่อไปขอให้พิจารณากรณีการเปลี่ยนเลขฐานสิบที่เป็นเลขทศนิยมให้เป็นเลขฐานสองดังแสดงในตารางที่ ๔



ตารางที่ ๔ ตัวอย่างตัวเลขฐาน 10 ที่เป็นเลขทศนิยมและตัวเลขฐาน 2 ที่เทียบเท่ากันหรือใกล้เคียงกัน


เลขฐาน 10
เลขฐานสอง
0.1
0.0001100110011.....
0.3
0.0100110011001.....
0.5
0.1
0.75
0.11
0.93359375
0.11111111

ตัวอย่างในตารางที่ ๔ แสดงให้เห็นว่ามีเลขทศนิยมในระบบเลขฐาน 10 บางจำนวนเท่านั้นที่สามารถหาเลขทศนิยมในระบบเลขฐาน 2 ที่มีค่าเท่ากันได้
 
ตัวเลขเช่น 0.5, 0.25, 0.125, 0.0625 ฯลฯ เป็นตัวเลขทศนิยมในระบบเลขฐาน 10 ที่สามารถแทนด้วยค่าตัวเลขทศนิยมในระบบเลขฐานสองที่มีค่าเท่ากันได้ ส่วนค่า 0.1 ในระบบเลขฐาน 10 จะมีค่าเป็นทศนิยมไม่รู้จบในระบบเลขฐาน 2 ดังนั้นเมื่อทำการป้อนข้อมูลที่มีค่าเท่ากับ 0.1 ในระบบเลขฐาน10 เข้าไปในคอมพิวเตอร์ คอมพิวเตอร์จะทำการแทนค่าด้วยเลขฐาน 2 ที่มีค่า "ใกล้เคียง" กับเลข 0.1 ในระบบเลขฐาน 10 กล่าวอีกนัยหนึ่งคือเรามีความคลาดเคลื่อน (error) เกิดขึ้นโดยที่เรายังไม่ได้เริ่มทำการคำนวณเลย
 
เวลาที่เราสั่งให้คอมพิวเตอร์เก็บค่าตัวเลข (ที่ไม่มีทศนิยม) ในรูป "จำนวนเต็ม" นั้น เช่นเลข 100 คอมพิวเตอร์ก็จะแปลงเป็นเลขฐาน 2 คือ 1100100 ซึ่งเป็นจำนวนที่เทียบเท่ากับพอดี แต่ถ้าเราสั่งให้มันเก็บค่า 100 ในรูปแบบ "จำนวนจริง" มันก็จะเก็บค่าในรูปแบบทำนอง 0.1 x 102 (อันที่จริงก็ไม่ใช่แบบนี้ เพียงแต่ต้องการเขียนให้เห็นภาพหน่อย) ซึ่งถ้าจะว่ากันทางคณิตศาสตร์แล้วมันก็ควรเท่ากับ 100 แต่ปัญหาก็คือเลข 0.1 ในระบบฐาน 10 นั้น มันไม่มีเลขในระบบฐาน 2 ที่ "เท่ากันพอดี" สิ่งที่เครื่องมันทำให้ก็คือมันจะหาเลขฐาน 2 ที่ใกล้เคียงที่สุดให้ ส่วนจะใกล้ได้มากแค่ไหนนั้นก็ขึ้นอยู่กับว่าเราใช้จำนวนบิท (bit) มากน้อยเท่าใดในการเก็บข้อมูล ในทำนองเดียวกันถ้าเราให้มันเก็บค่าตัวเลข 0.001 ในระบบฐาน 10 มันก็จะแปลงค่าเป็น 0.1 x 10-2 ซึ่งก็จะมีปัญหาว่ามันจะหาค่าในระบบฐาน 2 ที่ใกล้เคียงที่สุดให้
 
ผลที่ตามมาก็คือ เรายังไม่ได้เริ่มทำการคำนวณเลย เราก็มีความคลาดเคลื่อนในการคำนวณแล้ว
 
ผลของความคลาดเคลื่อนตรงนี้ทดลองเองได้ไม่ยากครับ ลองเปิดโปรแกรม spread sheet ขึ้นมา แล้วลองป้อนเลข 0.1 เรียงแถวลงไปในคอลัมน์ด้านซ้าย (เขียนเยอะหลายสิบตัวหน่อย) จากนั้นก็ลองใช้คำสั่ง sum ดูทุก ๆ 10 จำนวนดูก็ได้ครับ แล้วดูว่าค่าผลลัพธ์ที่ได้นั้นเป็นอย่างไร



ตารางที่ ๕ ผลรวมของค่า 0.1 (คำนวณด้วยโปรแกรม spread sheet OpenOffice 4.1.5)

1
1.000000000000000E-01

2
1.000000000000000E-01

---
---

10
1.000000000000000E-01
1.000000000000000E+00
11
1.000000000000000E-01

---
---

20
1.000000000000000E-01
2.000000000000000E+00
21
1.000000000000000E-01

---
---

30
1.000000000000000E-01
3.000000000000000E+00
31
1.000000000000000E-01

---
---

40
1.000000000000000E-01
4.000000000000000E+00
41
1.000000000000000E-01

---
---

50
1.000000000000000E-01
5.000000000000000E+00
51
1.000000000000000E-01

---
---

60
1.000000000000000E-01
6.000000000000000E+00
61
1.000000000000000E-01

---
---

70
1.000000000000000E-01
6.999999999999990E+00
71
1.000000000000000E-01

---
---

80
1.000000000000000E-01
7.999999999999990E+00


ผลการคำนวณที่แสดงในตารางที่ ๕ อันที่จริงเคยทำไว้ตั้งแต่สมัยใช้คอม 16 บิท พอเปลี่ยนเป็น 32 บิทหรือ 64 บิทก็ยังพบปัญหาแบบเดียวกันอยู่ เพียงแต่พบช้าลงเท่านั้นเอง ตอนที่เอา 0.1 จำนวน 10 20 ไปจนถึง 60 ตัวมารวมกัน ผลลรวมออกมาก็เป็น 1 2 3 4 5 และ 6 ดังที่เราคิดว่ามันควรเป็น แต่พอเอา 0.1 จำนวน 70 ตัวมาบวกเข้าด้วยกัน ปรากฏว่าไม่ได้ 7 กลับได้ 6.999999.... และหลังจากนั้นก็ได้ผลที่น้อยกว่าค่าที่ควรจะเป็นเสมอ ส่วนที่ว่าจะเห็นปรากฏการณ์นี้เมื่อใดนั้นขึ้นอยู่กับว่าคุณใช้กี่บิทในการเก็บข้อมูล ถ้าใช้จำนวนบิทมากก็จะเห็นมันเกิดช้าหน่อย แต่ก็ยังเกิดอยู่ดี 
  
ส่วนที่ว่าเครื่องนั้นให้ความละเอียดมากน้อยแค่ไหน ก็ลองเพิ่มจำนวนจุดทศนิยมให้มันเขียนรายงานผล ถ้าพบว่าเมื่อใดที่เพิ่มแล้วตำแหน่งท้ายสุดนั้นมันมีค่าเป็น 0 ตลอด นั่นก็แสดงว่าจุดนั้นมันเกินความละเอียดของเครื่องแล้ว อย่างในตารางที่ ๕ ก็อยู่ที่ 15 ตำแหน่ง
 
ตารางที่ ๖ เป็นอีกตัวอย่างหนึ่งที่จะไปทดลองเล่นดูเองกับโปรแกรม spread sheetก็ได้ครับ ตัวเลข 0.3333... ในคอลัมน์ข้างซ้ายผมคำนวณด้วยคำสั่ง 1/3 จากนั้นก็นำมาบวกรวมกัน ส่วนคอลัมน์ข้างขวานั้นผมป้อนตัวเลข 0.3333... ลงไปโดยตรงโดยให้ตัวเลขที่ "แสดงผลบนหน้าจอ" เหมือนกับตัวเลขในคอลัมน์ด้านซ้าย จากนั้นก็นำมาบวกรวมกัน จะเห็นว่าผลลัพธ์ที่ได้นั้นแตกต่างกันอยู่เล็กน้อยที่ทศนิยมตำแหน่งสุดท้าย (ที่ไฮไลต์ตัวหนาสีแดงเอาไว้) นั่นแสดงว่าตัวเลขที่เครื่องแสดงผลออกมาทางหน้าจอ แม้ว่ามันจะเหมือนกัน แต่สิ่งที่อยู่ในหน่วยความจำของมันนั้นมันแตกต่างกันอยู่



ตารางที่ ๖ ผลรวมของตัวเลขจำนวน 3 จำนวนที่ "เหมือนกัน"



คำนวณจาก 1/3

พิมพ์ตัวเลขลงไปโดยตรง

0.333333333333333000

0.333333333333333000

0.333333333333333000

0.333333333333333000
รวม
0.666666666666667000

0.666666666666666000



ผลจากการที่เครื่องไม่สามารถหาเลขฐาน 2 ที่เทียบเท่ากับเลขทศนิยมในระบบฐาน 10 ได้ทุกจำนวน ที่ทำให้ผลการคำนวณที่ได้นั้นมีความผิดเพี้ยนไป จะเห็นได้ชัดเจนและรวดเร็วแค่ไหนนั้นขึ้นอยู่กับว่าเราใช้กี่บิทในการเก็บข้อมูล ยิ่งใช้บิทมากก็ยิ่งช่วยบรรเทาผลกระทบนี้ แต่ใช้ว่ามันจะหายไป มันก็ยังมีอยู่ แต่อาจเห็นได้ไม่ชัดเจนนัก เว้นแต่จะมีจำนวนครั้งการคำนวณที่มาก (ดังนั้นถ้านำสิ่งที่แนะนำนี้ไปทดสอบด้วยเครื่องคอมพิวเตอร์ต่างระบบกัน ก็อาจให้ผลที่แตกต่างกันไปได้) ด้วยเหตุนี้บางโปรแกรมจึงมีคำสั่งให้เพิ่มจำนวนบิทเก็บข้อมูลขึ้นเป็น 2 เท่า (เช่นคำสั่ง Double precision ในภาษา FORTRAN ที่ผมเรียนมา) แต่นั่นก็หมายถึงหน่วยความจำที่ต้องการมากขึ้นและเวลาที่ต้องใช้ในการคำนวณที่เพิ่มมากขึ้นตามไปด้วย

ไม่มีความคิดเห็น: