ผมเรียนการคำนวณเชิงตัวเลขด้วยการใช้คอมพิวเตอร์ในยุคสมัยที่หน่วยความจำของคอมพิวเตอร์นั้นมีจำกัดมาก
ตอนที่คำนวณบนเครื่อง
mainframe
หรือ
mini
ก็ไม่ค่อยมีปัญหามากนัก
ที่มีปัญหามากกว่าคือเมื่อย้ายโปรแกรมมาทำงานบนเครื่อง
workstation
หรือ
micro
computer โดยเฉพาะ
micro
computer ที่ใช้ระบบปฏิบัติการ
DOS
ที่มองเห็นหน่วยความจำแค่
1
MB แต่ใน
1
MB นี้
DOS
ยึดไปก่อนแล้ว
384
kB (ช่วงเหนือ
640
kB - 1024 kB หน่วยความจำส่วนนี้เรียกว่า
upper
memory area) เหลือให้โปรแกรมต่าง
ๆ ใช่เพียงแค่ 640
kB (ช่วง
0-640
kB ที่เรียกว่า
conventional
memory) ซึ่งใน
640
kB นี้หลังจากที่เปิดเครื่องและคอมมันโหลด
driver
ต่างๆ
เข้าไปแล้ว ถ้าปรับแต่งดี
ๆ ก็อาจได้หน่วยความจำที่ใช้เป็นที่เก็บข้อมูลในการคำนวณได้สัก
200-300
kB (1 MB เท่ากับ
1024
kB นะ)
แต่ตอนหลังพอหน่วยความจำมีราคาถูกลง
ก็เลยมีความพยายามจะให้
DOS
เรียกใช้หน่วยความจำที่อยู่สูงเกินกว่า
1
MB ได้
ตรงนี้ก็เลยมีการจัดหน่วยความจำโดยแบ่งออกเป็น
high
memory area, extended memory และ
expanded
memory (แค่นี้ก็ทำให้ผู้ใช้งานงงไปหมดแล้ว)
ชิปสำหรับไมโครคอมพิวเตอร์ตระกูล
Intel
ที่เริ่มจาก
8086
หรือ
8088
นั้น
เป็นชิปสำหรับใช้งานประมวลผลทั่วไป
ถ้าต้องการเน้นการคำนวณเป็นหลัก
จะต้องซื้อชิปเพิ่มเติมที่เรียกว่า
Math
co-processor ติดตั้งเพิ่มเติม
ชิปตัวนี้ลงท้ายด้วยเลข 7
คือ
8087,
80287 และ
80387
แต่พอ
Intel
ออกซีพียูรุ่น
80486
กลับไม่มีชิป
80487
แต่ใช้วิธีให้ผู้ใช้เลือกว่าจะซื้อซีพียู
80486
ชนิดที่มีการรวมฟังก์ชัน
Math
co-processor เอาไว้ในตัว
(รุ่น
486DX)
หรือรุ่นที่ไม่มีฟังก์ชันนี้
(486SX)
ด้วยเหตุนี้เวลาที่เราเขียนโปรแกรมเสร็จ
ก็ต้องทำการ compile
โปรแกรมให้เป็นนามสกุล
.EXE
เพื่อให้มันทำงานได้
ตอนนั้น compiler
ที่ผมใช้
(FORTRAN)
มันมีให้เลือกว่าจะให้เรียกใช้
Math
co-processor หรือไม่
ถ้าเลือกว่าให้เรียกใช้และเครื่องที่ทำการ
run
โปรแกรมไฟล์
.EXE
นั้นมี
Math
co-processor โปรแกรมนั้นก็จะทำงานได้เร็ว
แต่ถ้านำโปรแกรม .EXE
ที่ได้นั้นไป
run
บนเครื่องที่ไม่มี
Math
co-processor มันก็จะทำงานไม่ได้
ในทางกลับกันถ้าบอกกับ
compiler
ว่าไม่มีการเรียกใช้
Math
co-processor โปรแกรม
.EXE
มันจะ
run
บนเครื่องได้ทุกเครื่อง
ไม่ว่าเครื่องนั้นจะมีหรือไม่มี
Math
co-processor หรือไม่
(ถึงมีมันก็ไม่เรียกใช้)
นอกจากนี้ยังมีให้เลือกว่าจะให้ไฟล์
.EXE
ที่ได้นั้นเน้นไปที่ทำงานได้เร็วหรือประหยัดหน่วยความจำ
ถ้าให้เน้นไปที่ทำงานได้เร็วก็จะได้ไฟล์
.EXE
ขนาดใหญ่
แต่ถ้าเน้นไปที่ประหยัดหน่วยความจำก็จะได้ไฟล์
.EXE
ขนาดเล็ก
แถมตัวซอร์ฟแวร์เองจะตั้งค่าการคำนวณไว้ที
single
precision หรือนัยสำคัญ
8
ตำแหน่งเป็นค่า
default
เอาไว้ก่อน
(เพื่อประหยัดหน่วยความจำ)
ถ้าต้องการความถูกต้องมากขึ้นไปอีกก็ต้องทำการกำหนดเองว่าจะใช้
double
precision หรือนัยสำคัญ
16
ตำแหน่ง
ซึ่งแน่นอนว่ากินหน่วยความจำเพิ่มมากขึ้นไปอีก
ด้วยเหตุนี้เมื่อสัก
๒๐ กว่าปีที่แล้ว คนที่ทำงานด้าน
numerical
simulation
นั้นจึงจำเป็นต้องรู้จักการทำงานของฮาร์ดแวร์ที่ตัวเองใช้ด้วย
ไม่ใช่รู้แต่เพียงแค่วิธีใช้ซอร์ฟแวร์
ทั้งนี้เพราะเวลาเปลี่ยน
platform
ของเครื่อง
(คือเปลี่ยนยี่ห้อผู้ผลิต
mainframe)
ระบบมันก็มีความแตกต่างกันอยู่ในบางจุด
มันไม่เหมือนกันซะทีเดียว
ในยุคปัจจุบันที่หน่วยความจำมีราคาถูกลงมาก
ชนิดที่เรียกว่าการคำนวณบนเครื่องไมโครคอมพิวเตอร์ตั้งความถูกต้องเอาไว้ที่นัยสำคัญ
16
ตำแหน่งเป็นหลัก
และการสอนการเขียนโปรแกรมด้วยภาษาสำหรับใช้เพื่อการคำนวณโดยเฉพาะ
ถูกเปลี่ยนไปเป็นการเขียนโปรแกรมด้วยภาษาสำหรับงานที่ไม่ได้มีการคำนวณมากนัก
ประกอบกับการมีซอร์ฟแวร์สำเร็จรูปให้เลือกใช้กันอย่างแพร่หลาย
ไม่จำเป็นต้องมานั่งเขียนโปรแกรมเองเหมือนแต่ก่อน
ทำให้ปัญหาสำคัญบางเรื่องที่ผู้ใช้คอมพิวเตอร์แต่ก่อนต้องเรียนรู้และต้องระมัดระวัง
กลับไม่มีการสอนในปัจจุบัน
ทั้ง ๆ ที่ปัญหาดังกล่าวก็ยังคงมีอยู่
รูปต่าง
ๆ ที่ยกมาเป็นตัวอย่างใน
Memoir
ฉบับนี้
ผมคำนวณด้วยเครื่อง pentium
4 2.4 GHz ติดตั้ง
ram
412 MB (เครื่องที่ภาควิชาจัดสรรให้บุคลากรใช้)
ใช้ระบบปฏิบัติการ
Windows
XP sp2 และใช้โปรแกรม
spreadsheet
ของ
OpenOffice
3.3.0 และ
Excel
ของ
Microsoft
Office 2007 คำนวณเปรียบเทียบกัน
ตัวอย่างที่ยกมาให้ดู ๓
ตัวอย่างนี้อยากให้ไปทดลองกับเครื่องของแต่ละท่านเอาเองว่ามันเป็นจริงไหม
แต่ว่ามันอาจแตกต่างกันไปบ้างได้
ขึ้นอยู่กับ spec
เครื่องที่ใช้
เราเริ่มเลยก็แล้วกัน
ตัวอย่างที่
๑ การคำนวณค่า
(1
+ e -1) และ
(1
- 1 + e)
ในทางทฤษฎีแล้วค่า
(1
+ e -1) และ
(1
- 1 + e) จะต้องเท่ากัน
และถ้าคิดเลขในใจผลก็จะออกมาเป็นเช่นนั้น
แต่เมื่อทำการคิดเลขบนไมโครคอมพิวเตอร์
(ใช้โปรแกรม
spreadsheet
ของ
OpenOffice
3.3.0) ที่ค่า
e
ต่าง
ๆ กัน ผลก็ออกมาเป็นดังแสดงในรูปที่
๑ จะเห็นว่าการคำนวณเมื่อเขียนคำสั่งแบบ
(1
- 1 + e) นั้นให้คำตอบที่ถูกต้องเสมอ
ในขณะที่การเขียนคำสั่งแบบ
(1
+ e -1) กลับให้คำตอบที่ผิดเพี้ยนไปจากคำตอบที่ถูกต้องเมื่อ
e
มีค่าเพียงแค่
.001
และหนักข้อขึ้นไปอีกเมื่อค่า
e
ลดต่ำลงเป็น
0.000
000 000 000 001 หรือต่ำกว่า
เพราะให้คำตอบที่ผิดไปเลย
(คือให้ค่าเป็นศูนย์)
อธิบายได้ไหมครับว่าเป็นเพราะอะไร
:)
:) :)
รูปที่
๑ ผลการคำนวณค่า (1
+ e -1) และ
(1
- 1 + e) ที่ค่า
e
ต่าง
ๆ กัน
แม้ว่าในทางทฤษฎีแล้วทั้งสองรูปแบบจะต้องให้คำตอบเดียวกัน
แต่ในทางปฏิบัติเมื่อนำมาคำนวณด้วยเครื่องคอมพิวเตอร์กลับพบว่าคำตอบแตกต่างกัน
ตัวอย่างที่
๒ ผลรวมของ
(1/3
+ 1/3 + 1/3)
รูปที่
๒ ข้างล่างเป็นตัวอย่างการคำนวณค่า
(1/3
+ 1/3 + 1/3) ด้วยวิธีที่แตกต่างกัน
3
วิธี
โดยในคอลัมน์ A
นั้นตัวเลขในช่อง
A27,
A28 และ
A29
ได้มาจากการให้เครื่องคำนวณค่า
1/3
และค่าในช่อง
A30
นั้นเป็นการเอาตัวเลขในช่อง
A27,
A28 และ
A29
มาบวกรวมเข้าด้วยกัน
ในคอลัมน์
B
นั้น
ตัวเลขในช่อง B27
ได้มาจากการคัดลอกตัวเลขในคอลัมน์
A27
ด้วยการใช้คำสั่ง
paste
special ที่คัดลอกมาเฉพาะค่า
(valve)
และรูปแบบ
(format)
ตัวเลขในช่อง
B28
และ
B29
ก็ได้มาจากช่อง
A28
และ
A29
ด้วยวิธีการเดียวกัน
ส่วนตัวเลขในช่อง B30
ก็เป็นการเอาตัวเลขในช่อง
B27,
B28 และ
B29
มาบวกเข้าด้วยกัน
ในคอลัมน์
C
นั้นผมใช้วิธีการป้อนค่าตัวเลขเข้าไปโดยตรง
โดยเลื่อนเคอร์เซอร์ไปที่ช่อง
B27
เพื่อดูว่าตัวเลขที่ปรากฏในช่อง
B27
นั้นเป็นตัวเลขอะไร
และก็กดคีย์บอร์ดตัวเลขนั้นลงในช่อง
C27
ตัวเลขในช่อง
C28
และ
C29
ก็ได้มาโดยวิธีการทำนองเดียวกัน
และตัวเลขในช่อง C30
ก็เป็นการเอาตัวเลขในช่อง
C27,
C28 และ
C29
มาบวกเข้าด้วยกัน
แต่คราวนี้ปรากฏว่าตัวเลขในช่อง
C30
นั้นแตกต่างไปจากตัวเลขในช่อง
A30
และ
B30
ทั้ง
ๆ ที่ตัวเลขที่ปรากฏในแถวที่
27-29
นั้นต่างก็เป็นตัวเลขเดียวกัน
รูปที่
๒ การคำนวณค่าผลรวมของ
(1/3
+ 1/3 + 1/3) จะเห็นว่าแม้ว่าตัวเลขค่า
1/3
ที่ปรากฏในแต่ละคอลัมน์นั้นจะเป็นเลขเดียวกัน
แต่เมื่อคำนวณผลรวมเข้าด้วยกันแล้วกลับได้ตัวเลขที่แตกต่างกันได้
ตัวอย่างที่
๓ การหาค่า
1.001
ยกกำลัง
8
การคิดค่า
xy
นั้นมีวิธีทำอยู่ด้วยกัน
๓ วิธีคือ
วิธีแรก
คือการคูณเข้าด้วยกันโดยตรงในรูป
x*x*....*x
วิธีนี้ใช้ได้ก็ต่อเมื่อ
y
เป็นเลขจำนวนเต็ม
วิธีที่สอง
ถ้าซอร์ฟแวร์มีคำสั่งยกกำลัง
เช่น **
ในภาษา
FORTRAN
หรือ
^
ในภาษา
BASIC
และในโปรแกรม
spreadsheet
ต่าง
ๆ)
ก็สามารถใช้คำสั่งนี้
เช่นเขียนเป็น x**y
หรือ
x^y
วิธีที่สาม
ในกรณีที่ซอร์ฟแวร์ไม่มีคำสั่งยกกำลัง
(ภาษาบางภาษาเป็นเช่นนั้น)
จะใช้วิธี
take
log ก่อน
จากนั้นจึงค่อยทำการ anti
log กลับกล่าวคือ
xy
= anti log (y *lgg x)) ส่วน
log
นั้นจะเป็นฐาน
e
หรือฐาน
10
ก็ตามแต่
รูปที่
๓ เป็นผลการคำนวณค่า 1.0018
ด้วยการใช้วิธีการทั้ง
๓ ที่กล่าวมาข้างต้น
บรรทัดแรกใช้การ take
log ฐาน
e
แล้วค่อยทำการ
anti
log กลับ
บรรทัดที่สองก็เป็นแบบเดียวกับบรรทัดแรก
แต่เปลี่ยนเป็นฐาน 10
บรรทัดที่
3
เป็นการนำตัวเลข
1.001
จำนวน
8
ตัวมาคูณเข้าด้วยกันโดยตรง
และบรรทัดที่สี่เป็นการใช้คำสั่งยกกำลัง
รูปที่
๓ (บน)
นั้นคำนวณด้วยการใช้โปรแกรม
OpenOffice
3.3.0 ส่วนรูปที่
๓ (ล่าง)
นั้นใช้โปรแกรม
Excel
2007 จะเห็นว่าโปรแกรม
OpenOffice
3.3.0 นั้นไม่ว่าจะใช้วิธีการไหนจะให้คำตอบที่เหมือนกันหมด
แต่ในกรณีของโปรแกรม Excel
นั้นการใช้วิธี
take
log ก่อนแล้วค่อยทำการ
anti
log กลับนั้นให้ค่าที่เหมือนกับค่าที่ได้จากโปรแกรม
OpenOffice
3.3.0 แต่พอใช้วิธีการคูณเข้าด้วยกันโดยตรงหรือใช้คำสั่งยกกำลัง
กลับได้ค่าที่แตกต่างไป
(ตัวเลขหลักสุดท้าย)
รูปที่ ๓ การคำนวณค่า (1.001)8 ด้วยวิธีที่แตกต่างกัน 4 วิธีและใช้โปรแกรมต่างกัน (คำนวณบนเครื่องเดียวกัน) โดยรูปบนเป็นผลการคำนวณโดยใช้โปรแกรม spreadsheet ของ OpenOffice 3.3.0 ส่วนรูปร่างเป็นผลการคำนวณด้วยโปรแกรม Excel ของ Mircosoft
ตัวเลขที่แสดงนั้นใช้ตัวเลข
15
หลัก
คือความละเอียดสูงสุดเท่าที่เครื่องจะให้ได้
15
หลักนี้มาจากการที่ให้เครื่องคำนวณตัวเลขสักตัวที่มันเป็นทศนิยมไม่รู้จบ
(เช่น
1/3)
แล้วเพิ่มจำนวนจุดทศนิยมให้มันเขียน
เมื่อไรก็ตามที่ตำแหน่งสุดท้ายนั้นเป็นศูนย์ก็แสดงว่าเครื่องมันให้ความละเอียดได้มากที่สุดเท่านั้น
ตัวอย่างที่ยกมานี้อาจเปลี่ยนไปตามซอร์ฟแวร์และฮาร์ดแวร์ที่ใช้
ส่วนเหตุผลที่ว่าทำไมมันจึงเป็นเช่นนั้น
ก็ฝากให้เอาไปคิดกันเล่น
ๆ ก่อนก็แลัวกัน
เพราะบางเรื่องมันมีสาเหตุมาจากฮาร์ดแวร์
และบางเรื่องมันก็มีสาเหตุมาจากซอร์ฟแวร์
ไม่มีความคิดเห็น:
แสดงความคิดเห็น