Sunday, November 25, 2007

ร้านกาแฟหกรด


ไปเจอร้านกาแฟนี้ใน San Francisco ชื่อร้านมันตลกมากจนต้องเอามาให้ดู!

Monday, June 11, 2007

หัดออกเสียงแบบชาว California: เดาเสียง s z จากตัวสะกด

ไม่ได้เขียนอะไรใน blog นี้ประมาณเวลาตั้งครรภ์ได้ ตอนนี้ใกล้จะกลับไทยแล้ว ก็ขอเขียนซักหน่อยละกัน :P

เนื่องด้วยภาษาอังกฤษที่เราเรียนในเมืองไทย เน้นให้อ่านออก เขียนได้ แต่ไม่ได้ให้ออกเสียงถูก พอมีโอกาสมาอยู่เมืองนอกแล้ว มันก็น่าจะฝึกส่วนที่ขาดหายไปใช่มะ แล้วก็สำเนียงภาษาอังกฤษของคนแถวนี้ (California) เค้าถือว่ามาตรฐานของ American English ด้วย ไหน ๆ มาอยู่ Stanford แล้ว ก็ลงเรียนวิชา Pronunciation ซะเลย :D ตอนแรกก็ไม่นึกหรอกว่ามันจะน่าสนใจขนาดนี้ เรียน ๆ ไป รู้สึกว่ามีสิ่งที่ไม่รู้เยอะแฮะ (แต่เรียนจบคอร์สแล้ว สำเนียงก็เหมือน ๆ เดิมอะนะ)

คิดว่าหลาย ๆ คนที่เรียนอังกฤษในเมืองไทยคงยังไม่เคยรู้เรื่องพวกนี้ ก็เลยจะเอามาฝากกันนี่แหละ (American English อย่างเดียวนะ)

เสียง s กับ z

คิดว่าทุกคนคงรู้อยู่แล้วว่า s มีเสียงเหมือน "ซ" หรือ "ส" ในภาษาไทย ส่วนตัว z เนี่ย ถึงเราจะไม่มีตัวอักษรที่ออกเสียงเหมือนกัน แต่คิดว่าตัวนี้ไม่น่าจะเป็นปัญหากับคนไทย ถ้าใครไม่รู้ว่า z ออกเสียงยังไง ก็ทำเสียง s (ไม่ได้ออกจากกล่องเสียง) แล้วพยายามเติมเสียงจากกล่องเสียง มันก็จะเป็น z เอง (อันนี้ง่าย)

แล้วเมื่อไหร่ใช้ s เมื่อไหร่ใช้ z หละ?

จะว่าไปมันก็เป็นเรื่องแปลก (คนที่รู้ก็คงไม่แปลกหรอก) ที่คำที่สะกดด้วยตัว s อ่านออกมาเป็น z เยอะมาก กฎสำหรับออกเสียง z เวลาเห็นตัว s ก็มีหลัก ๆ คือ
  1. s ใน -s ที่ใช้เป็นตัวสุดท้ายของคำ ตามหลังเสียง voiced consonant (ไว้จะพูดถึงอีกที) เช่น pens
  2. s ใน -es ท้ายคำที่เป็นพหูพจน์ (ให้ออกเสียงว่า อิซซ ด้วย z)
  3. คำว่า is his Ms.
  4. -sn't -sm เช่น anarchism
ส่วนกฎสำหรับออกเสียง s เวลาเห็นตัว s ก็มีคร่าว ๆ คือ
  1. ss
  2. s ที่ขึ้นต้นคำ และไม่ได้ตามด้วย h, ch
  3. s ที่ลงท้าย prefix เช่น misapprehend disavow
  4. s หลังสระเสียงสั้น (ยกเว้น is his Ms.) เช่น this promise pus
  5. s ใน -s ที่ใช้เป็นตัวสุดท้ายของคำ ตามหลังเสียง voiceless consonant
  6. s หลังพยัญชนะ หน้าสระ เช่น insensitive absinthe lapse alongside forsake
  7. -s? เมื่อ ? เป็นพยัญชนะ voiceless เช่น anarchist
  8. คำ 1 พยางค์ที่ลงท้ายด้วย -ase กับ -oose
นอกจากกฎพวกนี้ ก็คงต้องจำกันแล้วหละ ตัวอย่างที่ต้องจำเช่น:
  • s หลังสระเสียงยาวใน verb มักจะเป็น z เช่น realise refuse lose ease appease please แต่ loose grease lease cease crease increase decrease decease ใช้เสียง s
  • s หลังสระเสียงยาวในคำที่ไม่มีรูป verb มักจะเป็น s เช่น dose verbose close(adj) แต่ cheese disease ใช้เสียง z
  • คำบางคำอ่านต่างกันเมื่อเป็น noun กับ verb เช่น use กับ house ใช้ s เมื่อเป็น noun ใช้ z เมื่อเป็น verb
  • close ที่แปลว่าใกล้ (adjective กับ adverb) ใช้เสียง s ส่วน close ที่แปลว่าปิด (noun กับ verb) ใช้เสียง z
  • douse louse mouse ใช้เสียง s แต่ rouse spouse ใช้เสียง z
  • precise กับ concise ใช้เสียง s ส่วน incise exercise ฯลฯ ใช้เสียง z (ข้อสังเกตุ: precise กับ concise ไม่มีรูป verb)
  • garrison ใช้เสียง s แต่ visage ใช้เสียง z
เสียง "ซ" หรือ "ส" ที่มาจาก c หรือ sc ให้ออกเสียงเป็น s ทั้งหมด ส่วนที่มาจากตัว z ให้ออกเป็น z ทั้งหมด ยกเว้นคำ Italian (pizza, mezzo, ...) ให้ออกเป็นเสียง s

ตัวอย่าง: เสียงสระเหมือนกัน ทางซ้ายเสียง s ทางขวาเสียง z
place - plays
ice - eyes
miss - Ms.
price - prize
hence - hens
dense - dens
rice - rise
race - raise
race - rays
race - raze
loose - lose
goose - goos
hiss - his
use(noun) - use(verb)
face - phase
bus - buzz
ass - as
lense - lens
(lense กับ lens ความหมายเหมือนกันนะ)
decease - disease
(s ใน decease ใช้เสียง s ส่วน s ทั้งสองที่ใน disease ใช้เสียง z)
close(adj) - close(v)
close(adj) - clothes(n)

ตัวอย่างเปรียบเทียบตัวสะกด ทางซ้ายเสียง s ทางขวาเสียง z (เสียงอื่น ๆ ก็ต่างกัน):
racist - racism
purpose - propose
(purpose สระเสียงสั้น propose สระเสียงยาว)
promise - compromise
(promise สระเสียงสั้น compromise สระเสียงยาว)
analysis - analyses
(analyses เป็นรูปพหูพจน์ ... s ตัวแรกเป็นเสียง s ในทั้งสองคำนะ)
crease - ease
its - is
this - his
intense - intends
laps - labs
motes - modes
docks - dogs
strifes - strives

Wednesday, September 27, 2006

เรื่อง Stanford

จะบอกว่า ถ้าจะดูเรื่องเกี่ยวกะชีวิตนู้บสแตนฟอร์ดเนี่ย ให้ไปดูที่ Another Tunoblog แทน ขี้เกียจ update สองที่หนะ

Thursday, September 21, 2006

เด็กบ้านนอก - นู้บ

เผื่อคนที่ไม่รู้ ตอนนี้อยู่ที่ 119 Quillen Court, #500, Stanford CA 94305 นะ วันจันทร์จะเปิดเทอมแล้ว

ไปอยู่ในที่ใหม่ มันก็มีอะไรต้องศึกษาใหม่เยอะนะ ... สถานที่ก็ใหญ่ เดินทางก็ลำบาก ถึงจะฟรีก็เหอะ รู้สึกมันบ้านนอกบ้านนอกไงก็ไม่รู้

ไม่ค่อยมีเวลาเขียนเท่าไหร่เลย ช่วงนี้มีงานมีเหตุการณ์มากมาย ... ไว้มีเวลาแล้วจะมาเขียนอีกเยอะ ๆ ละกัน

ป.ล. เพิ่งรู้ว่า IE มันไม่ยอมให้เขียนสระอาติดกันหลาย ๆ ตัวใน Edit Box อะ แย่จัง

Thursday, August 10, 2006

Siam Paragon

คำอ่าน "Siam Paragon" เป็นภาษาไทยเนี่ย ...
  • สยามภาระก้น
  • สยามปลาร้าก้อน (เพี้ยนนิดหน่อย)
มีมากกว่านี้อีกปะ บอกหน่อย

Sunday, July 02, 2006

Programming: Space-Time Relation

ขอเริ่มต้น post ของวันนี้ด้วยการขอโทษก่อนละกัน วันนี้ (จริง ๆ เมื่อวานด้วย) ไม่ได้ไปเยี่ยมบัณฑิตจุฬา ฯ ที่ไปซ้อมรับปริญญา เพราะมีเหตุการณ์สำคัญเกิดขึ้นที่บ้าน ที่คนทั่ว ๆ ไปคงเรียกว่าปัญหาครอบครัวหนะ

แล้วก็ ... เตือนกันอีกครั้งนะ ... ถ้าจะดู post เก่า ๆ ให้มันเป็นลำดับดี ๆ ไปดูที่นี่


มันจะมี link มาที่หน้าของแต่ละ post ใน Tunoblog อันนี้

โปรโมตเสร็จ ก็ขอเข้าเรื่องละกัน คราวนี้จะพูดถึงความสัมพันธ์ระหว่าง ความเร็วของ algorithm กับเนื้อที่ memory ที่จะต้องใช้

สำหรับปัญหาปัญหานึง เราอาจจะมีวิธีแก้หลาย ๆ แบบ ซึ่งสำหรับนักเขียนโปรแกรมเนี่ย เค้ามักถามกันว่า "บิ๊กโอ (Big-O = O ใหญ่น่ะแหละ) เท่าไหร่?"

ใครที่ยังไม่รู้จัก O ตัวนี้ ก็ขอพูดคร่าว ๆ ละกัน

O(g) = { f | f(x) เพิ่มไม่เร็วกว่า g(x) เมื่อ x มีค่ามาก ๆ }

จริง ๆ นิยามแบบชัด ๆ มันก็มีอยู่อะนะ แต่ขี้เกียจยกมา ไปดูเอาเองจาก Wikipedia ละกัน :P

มาต่อกันเรื่องหลัก คราวนี้มาสนใจเรื่อง Space-Time ดีกว่า ...

ทฤษฎีสัมพัทธภาพ

ม่ายช่ายและ :P ... จะพูดถึง Big-O ของเวลา กับ เนื้อที่ memory ที่ algorithm ใช้ตะหาก

Sorting Algorithm

ปัญหาการเรียงข้อมูลเนี่ย เป็นปัญหาสุดคลาสสิก ที่น่าเอามาพูดถึงที่สุด วิธีการเรียงที่นิยมสอนกัน มักจะมีอยู่เท่านี้ (ขาดเกินบ้างนิดหน่อย)
  • Selection Sort - ใช้เวลา O(n2) เมื่อมีข้อมูล n ตัว
  • Bubble Sort - ใช้เวลา O(n2)
  • Insertion Sort - ใช้เวลา O(n2)
  • Shell Sort - ใช้เวลา O(n1.5) (จริง ๆ มี O(n log2n) นะ ดูที่นี่)
  • Merge Sort - ใช้เวลา O(n log n)
  • Quick Sort - ใช้เวลา O(n log n) (เฉลี่ย)
  • Heap Sort - ใช้เวลา O(n log n)
  • Bucket Sort - ใช้เวลา O(m + n)
  • Radix Sort - ใช้เวลา O(n log m)
เมื่อ n คือจำนวนข้อมูล และ m คือขนาดของ domain ของข้อมูล จะเห็นว่า 7 วิธีแรก ทำงานเร็วกว่า 2 วิธีสุดท้ายในกรณีที่ m มากกว่า n มาก ๆ

หนังสือทั่ว ๆ ไป มักจะไม่พูดถึงขนาดของ memory ที่ต้องใช้ เพราะว่า ไม่มีิอันไหนใช้เกิน O(n) ซึ่งเป็นขนาดของ input แต่เราจะลองมองดูซักนิดนะ ว่ามันเป็นยังไง
  • Selection Sort - ใช้เนื้อที่เพิ่ม O(1)
  • Bubble Sort - ใช้เนื้อที่เพิ่ม O(1)
  • Insertion Sort - ใช้เนื้อที่เพิ่ม O(1)
  • Shell Sort - ใช้เนื้อที่เพิ่ม O(1)
  • Merge Sort - ใช้เนื้อที่เพิ่ม O(n)
  • Quick Sort - ใช้เนื้อที่เพิ่ม O(log n) (เฉลี่ย)
  • Heap Sort - ใช้เนื้อที่เพิ่ม O(1)
  • Bucket Sort - ใช้เนื้อที่เพิ่ม O(m)
  • Radix Sort - ใช้เนื้อที่เพิ่ม O(1)
ดู ๆ ไปเหมือน Heap Sort น่าจะดีที่สุด แต่จริง ๆ แล้ว มันมีอะไรมากกว่านี้นิดนึง มาลองดูละเอียดดีกว่า ว่าแต่ละวิธี ต้องการสิ่งอะไรที่ต่าง ๆ กัน (แบบคร่าว ๆ)
  • Selection Sort - ลูป 2 ชั้น และตัวแปรพักข้อมูลสำหรับการสลับ
  • Bubble Sort - ลูป 2 ชั้น และตัวแปรพักข้อมูลสำหรับการสลับ
  • Insertion Sort - ลูป 2 ชั้น และตัวแปรพักข้อมูลสำหรับการแทรก
  • Shell Sort (กรณีเวลา O(n log2n)) - ลูป 3 ชั้น ตัวแปรสำหรับสร้างลำดับ 2 ตัว และตัวแปรพักข้อมูลสำหรับการสลับ หรือ แทรก
  • Merge Sort - Recursive 2 ครั้ง ลูป 1 ชั้นที่มีตัวนับ 2 ตัว กับ array พักข้อมูลความยาว n และลูปคัดลอกค่าจาก array พักข้อมูล
  • Quick Sort - ลูป 1 ชั้นที่มีตัวนับ 2 ตัว ตัวแปรพักข้อมูลสำหรับการสลับ และ Recursive 2 ครั้ง
  • Heap Sort - ลูป 2 ชั้น 2 ลูป และตัวแปรพักข้อมูลสำหรับการแทรก
  • Bucket Sort - ลูปกำหนดค่าเริ่มต้น (ใช้เวลา O(m)) ลูปรับ input และลูปแสดง output (ใช้เวลา O(n))
  • Radix Sort (ฐาน 2) - ลูป 2 ชั้น ชั้นนอกทำซ้ำ log2m ครั้ง ชั้นในมีตัวนับ 2 ตัว
ถ้าคิดความซับซ้อนของโปรแกรม เป็นเนื้อที่อีกประเภท เราก็พอจะคิดได้ว่า ถ้าใช้เนื้อที่มาก มันก็ทำงานเร็วนะ

Dynamic Programming - Fibonacci Function

อันนี้ คิดว่า หลาย ๆ คนคงคุ้นเคยและรู้อยู่แล้ว หน้าตามันก็ประมาณนี้ (ภาษา C ละกัน)

int fib(int n) { return n <= 1 ? 1 : fib(n - 1) + fib(n - 2); }

จะเห็นว่า code สั้นมาก ดังนั้น จากหลักของเรา พอจะเดาได้ว่า น่าจะมีวิธีทำให้มันทำงานเร็วกว่านี้ แต่ code ยาวกว่านี้ หรือมีตัวแปรเพิ่ม

ลองดูก่อน ว่า เขียนโปรแกรมแบบนี้ ใช้เวลาทำงานเท่าไหร่ ... คำตอบค่อนข้างง่ายนะ เวลาก็คือ O(fib(n)) น่ะแหละ (ว่าไปก็คือ O(αn) เมื่อ α = golden ratio น่ะแหละ)

มันกินเวลาน่าดูเลยนะเนี่ย ลองพยายามทำให้มันเร็วขึ้นสิ ... วิธีง่าย ๆ ก็คือ กำหนดตัวแปรเพิ่มเป็น array ความยาว n แล้วก็คิดค่าไล่ตั้งแต่ f(0) ถึง f(n) ไง หยั่งงี้ f(...) ตัวที่เคยคิดแล้ว ก็ไม่ต้องคิดซ้ำ

int fib(int n) { return a[n] > 0 ? a[n] : a[n] = fib(n - 1) + fib(n - 2); }

แล้วกำหนดค่าเริ่มต้นให้ a[0] = 1, a[1] = 1 และ a[อื่น ๆ] = -1

จริง ๆ มันประหยัดเนื้อที่ได้อีกนะ แต่คราวนี้โปรแกรมจะซับซ้อนละ ...

int fib(int n)
{
int f, last1, last2;
if (n <= 1) return 1;
last1 = 1;
last2 = 1;
for (--n; n > 0; --n)
{
f = last1 + last2;
last2 = last1;
last1 = f;
}
return f;
}

จะเห็นว่า เหลือตัวแปรแค่ 3 ตัว (คือ memory O(1)) แลกกับ code ที่ยาวขึ้นอีกนิดนึง

จริง ๆ ยังทำให้มันเร็วกว่านี้ได้อีกแหละ แต่คราวนี้ code จะยาวขึ้นเยอะเลย แล้วจะเร็วขึ้นเฉพาะเมื่อ n เยอะมาก ๆ ๆ ๆ ๆ เท่านั้น

เอาเป็นว่า หยุดแค่นี้ก่อนดีกว่า

Friday, June 30, 2006

Programming: Stack and Recursion

ไม่ยอมเขียนมาซะนาน ขอกลับมาทำบ้างซักครั้งละกัน ... คิดถึงจัง ความรู้สึกนี้ :D

คราวนี้จะพูดถึงเรื่องการเขียนโปรแกรมซักหน่อยนะ คาดว่าจะเป็นประโยชน์กับ programmer รุ่นเด็ก ๆ บ้างนะ

Stack and Recursion

หลาย ๆ คนคงรู้อยู่แล้วว่าทั้งสองอย่างนี้มันคืออะไร และมันเกี่ยวกันยังไง ... ใครไม่รู้อ่านต่อละกัน :P

Stack
  • กลุ่มข้อมูลคล้าย ๆ หลอด CD ที่ใช้เสียบแผ่นหลาย ๆ แผ่นเข้าด้วยกัน
  • คุณสมบัติก็คือ จะใส่เพิ่มหรือจะหยิบออก จะต้องทำจากข้างบน
Recursion
  • การทำซ้ำ ๆ ที่เกิดจากการฟังก์ชันที่เรียกกันเป็นวง เช่น f เรียก g แล้ว g เรียก h แล้ว h เรียก f ไปเรื่อย ๆ
  • สิ่งที่จำเป็นในการเขียนโปรแกรมแบบ Recursive ก็คือ จะต้องมีเงื่อนไขการหยุด
แล้วสองอย่างนี้ มันเกี่ยวข้องกันยังไงหละ?

จริง ๆ อยากให้ไปอ่านเรื่องที่ทำ Virtual Machine จัง แต่มันคงจะยาวไปเนอะ ... สรุปเลยละกัน :P ง่าย ๆ ก็คือ ... ทุกครั้งที่เรียกฟังก์ชัน เราต้องเพิ่มข้อมูลบางอย่างใน Stack ของ CPU แล้วพอฟังก์ชันทำงานเสร็จ เราก็จะเอาของพวกนั้นออก

แปลว่า ... ที่เราสามารถเขียนโปรแกรมแบบ recursive ได้เนี่ย ก็เพราะว่า CPU มันมี Stack อยู่

และก็แปลว่า ... เราสามารถสร้าง Stack ขึ้นเอง แล้วก็ไม่ต้องไปรบกวน Stack ของ CPU ได้เหมือนกัน

ลองดูตัวอย่างเลยละกัน สมมติว่าเรามีฟังก์ชันที่เขียนแบบ recursive ตัวนึง

 function f(x)
begin
  if x <= 0 then return 0;
else return 2x - 1 + f(x - 1);
 end

ถ้าเรามี Stack เราจะเขียนแบบไม่ recursive ได้เป็น

 function f(x)
begin
  push x onto Stack;
  push "not done" onto Stack;
  while Stack is not empty
  do
   assign op ← Top of Stack;
  Remove Top of Stack;
   assign x ← Top of Stack;
   Remove Top of Stack;
if op = "not done" then
begin
  push x onto Stack;
 push "done" onto Stack;
 if x <= 0 then do nothing;
 else
 begin
 push x - 1 onto Stack;
 push "not done" onto Stack;
 end
end
 else if op = "done" then
 begin
 if x <= 0 then assign ReturnValue ← 0;
else assign ReturnValue ← 2x - 1 + ReturnValue;
 end
  end while
  return ReturnValue;
 end

จะเห็นว่า มันยาวขึ้นมาก -_-'' จริง ๆ จะทำให้สั้นกว่านี้ก็ได้อีกเยอะหนะนะ แต่นี่เป็นตัวอย่างการแปลงแบบตรงไปตรงมา ฟังก์ชันอะไรเราก็แปลงแบบนี้ได้

แอบอัพเดท

โทษทีที่ยังไม่ได้เอารูปตอนไปยุโรปมาลงให้ จะเอามาให้ดูจริง ๆ แหละ แต่รอก่อนนะ ตอนนี้ขอแอบกลับไปเขียนเรื่องบ้า ๆ ต่อก่อน

Tuesday, June 27, 2006

ฟันคุด

ไปผ่าฟันคุดมาเมื่อวันศุกร์ที่แล้วหนะ . . . ผ่าข้างล่างสอง ถอนข้างบนสอง

ก่อนหน้านี้ มีคนขู่ไว้เพียบเลย - -'' พอทำเอง มันก็ไม่ได้น่ากลัวขนาดนั้นซะหน่อย

พอเจอหมอ หมอเค้าก็คุยก่อนนะ เค้าบอกว่า ฟันมันเอียงมาก (ประมาณ 70 องศา จากที่เห็นในฟิล์ม) เอียงเหมือนจะไปดันซี่ข้าง ๆ ด้วย ถ้าจะเอาออก จะต้องทำให้มันเป็นชิ้นเล็กชิ้นน้อยก่อน วิธีทำก็คือ ค่อย ๆ กรอเนื้อฟันออก จนมันบางลง ก็ออกแรกบีบให้มันแตก ... ฟังดูน่ากลัวมะ

พอถึงเวลาจริง ที่เจ็บที่สุดก็เห็นจะเป็นเข็มฉีดยาชานี่แหละ (มันก็ไม่ได้เจ็บมากหรอก บริจาคเลือดยังเจ็บกว่าอีก)

เริ่มแรก เค้าฉีดยาชาเสร็จแล้วก็รอแป๊บนึง แล้วก็เอาคีมมางัดแงะดึงฟันข้างบนออก เดี๋ยวเดียวเสร็จเลย รู้สึกว่าอะไร ๆ มันก็เร็วกว่าที่คิดนะ

แต่อีกสองซี่ที่ต้องทำให้เป็นชิ้น ๆ เนี่ย ใช้เวลานานกว่าที่คิดแฮะ

ช่วงที่รู้สึกเสียว ๆ ก็มีนะ ช่วงแรกคือ ตอนที่หมอกำลังขัดเนื้อฟันข้างขวาออกเนี่ย เค้าออกแรงเยอะมาก จนรู้สึกว่ามันตึงที่ข้างนอกเลย

อีกช่วงนึงก็ ... จริง ๆ ไม่ได้รู้สึกเจ็บหรือเสียวฟันอะนะ เป็นความเสียวทางความคิดหนะ คือประมาณว่า ผู้ช่วยหมอเค้าไม่ใส่แว่นแล้วมองเห็นไหมไม่ชัด (สีมันคล้าย ๆ น้ำลาย) หมอก็ต่อว่า ว่าถ้ามองไม่ชัด คราวหน้าต้องใส่แว่นมานะ ไม่งั้นไม่ต้องมาช่วย - -'' เสียวมั้ยหละ

แล้วหลังจากนั้นแป๊บเดียว หมอก็บอกอีกว่า ไหมเนี่ย ผู้ช่วยดึงไม่แน่น ... แล้วหมอก็ทำอะไรอีกก็ดูไม่รู้เรื่อง อาจจะเอาออก เย็บใหม่ก็ได้ (ยังไงตอนนี้ก็ดูไม่ออกแล้ว)

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

วันแรกหลังจากทำ ก็ไม่เจ็บนะ แค่รำคาญว่าเวลากินอะไร เศษมันจะติด ๆ แล้วเอาออกไม่ได้ แล้วก็เจ็บนิดหน่อยเวลากลืน เพราะว่ามีแผลที่ลิ้นนิดนึง

วันที่สองก็ รู้สึกเหมือนวันแรก ... ไม่ค่อยรู้สึกว่ามันจะดีขึ้นแฮะ - -''

วันที่สามเนี่ย เริ่มรู้สึกดีขึ้นละ แต่ก็ยังกินอะไรที่ต้องเคี้ยวไม่ได้หนะ ยังกินแต่ไข่ตุ๋น มันฝรั่งบด แล้วก็โจ๊ก

วันนี้วันที่สี่แล้ว ... ทำไมมันรู้สึกเจ็บ ๆ อะ T_T ... ความเจ็บมันมีการหน่วงเวลาด้วยแฮะ ...

Sunday, May 21, 2006

กลับมาละ

หลังจากวันจันทร์ที่แปดแล้ว ก็หาเน็ตไม่ได้เลยอ่า เอาเป็นว่า สรุปการไปเยือนเมืองนอกเอาทีเดียวเลยละกัน ... อ้อ ยังไม่ได้เอาภาพจากกล้องมาลงหนะ อ่านแห้ง ๆ ไปก่อนละกัน :P

ก็ ... ต่อจากตอนที่แล้ว ก็ไปโรงงานกะโรงแรม สลับกันไปเรื่อย ๆ หละ จนวันที่สิบสอง ก็ขึ้นเครื่องบินไป Venezia จากสนามบิน Marco Polo ก็มีคนมารับไปโรงแรมแถว ๆ Padova ชื่อว่า Ibis

ที่โรงแรมนี้ ลิฟท์ก็แปลกไปอีกแบบ คือมันไม่มีปุ่มเปิดประตู (โรงแรมที่แล้วไม่มีปุ่มปิด)

สภาพส่วนใหญ่ในโรงแรมนี้ ดีกว่าโรงแรมที่แล้วนะ แต่ว่า ... มันไม่มีเน็ต T_T

เย็นวันศุกร์ ได้ไปแวะซุปเปอร์มาร์เก็ตใกล้ ๆ โรงแรมด้วยหละ รู้สึกว่าของมันแพงจัง ... เดินอยู่ในนั้นพอประมาณ ก็ซื้อน้ำเปล่ามา กับขนมนิด ๆ หน่อย ๆ

พอวันเสาร์ ก็ไปเดินเล่นในเมือง Padova มีร้านเสื้อผ้า เครื่องแต่งกาย เยอะมาก แล้วก็มีตลาดนัดด้วย ดูคล้าย ๆ เมืองไทยเลยแต่ว่าบรรยากาศมันดีจัง ติดอยู่ตรงที่น้ำดื่มมันแพง ... เดิน ๆ แล้วหิวน้ำ ก็ไม่ค่อยอยากซื้อ

ตอนกลางวันกินข้าวที่ Pizzeria อะไรก็ไม่รู้ จำชื่อไม่ได้ สั่งพิซซ่ากินกับพ่อคนละถาด (ราคาถาดละแปดยูโร) ถาดมันใหญ่กว่าที่คิดแฮะ แต่ก็กินจนหมดได้หละน่า!

หลังจากนั้นก็เดิน ๆ ไปเรื่อย ๆ ไม่ได้ซื้ออะไรเลย :( ก็มันไม่มีอะไรน่าซื้อหนิ ): ขึ้นรถเมล์กลับโรงแรม แล้วก็กินข้าวเย็นที่โรงแรม ... จบวัน

วันอาทิตย์ ทุกอย่างปิดหมด รถเมล์ไม่วิ่ง ถ้าจะไปไหน ต้องเรียกแท็กซี่ราคาสุดโหด ก็เลยดิ้น ๆ อยู่แค่ในโรงแรม T_T นอนแต่หัวค่ำ เตรียมไปทำงานเช้าวันจันทร์

ประมาณแปดโมงครึ่ง (เช้า) วันจันทร์ ก็ไปที่โรงงานอีกแห่งนึง คุย ๆ กะเค้าถึงซักสิบโมงสิบห้านาทีโดยประมาณ ก็ต้องไปโรงงานอีกที่นึง ที่นี้อยู่ใน Belluno ซึ่งก็ไกลพอควรเลย นั่งรถไปประมาณสี่สิบห้านาที ยังอยู่ระหว่างทางไปโรงงาน ก็เห็นภูเขาอยู่สองข้างถนน มองไปไกล ๆ หน่อยจะเห็นยอดเขาสีขาว ๆ ปกคลุมด้วยหมอกและหิมะ ... ดูดีจัง

นั่งต่อไปอีกประมาณครึ่งชั่วโมง คราวนี้ทางขวามือไม่มีภูเขาแล้ว แต่เป็นเมืองแทน มองเมืองจากตรงนี้ก็สวยดีแฮะ

แล้วอีกประมาณสิบห้านาที ก็ถึงที่หมาย ... โรงงานอีกแห่ง

คุย ๆ กะเค้า ถึงประมาณบ่ายสาม ก็ต้องกลับ Venezia แล้ว เพราะว่าจะต้องขึ้นเครื่องบินกลับไป Roma เพื่อจะไปต่อเที่ยวบินไปยัง Frankfurt

กลับไปถึง Roma ก็ไม่มีโรงแรมพักในเมืองอีก ต้องออกจากเมือง ไปพักโรงแรมใน Pomezia (คนละโรงแรมกับครั้งแรกนะ) ปุ่มในลิฟท์ของโรงแรมนี้เนี่ย ... คราวนี้ มันมีเลข 0 ถึง 9 เรียงเหมือนเครื่องคิดเลขเลย แต่ตึกมันมีไม่ถึง 9 ชั้นอะ ...

นอน ตื่น วันอังคารละ คราวนี้ บินจากสนามบิน Fiumicino ไปสนามบิน Frankfurt

เห็นภาษาเยอรมันแล้ว รู้สึกว่าอ่านยากกว่าอิตาลีเยอะเลย (คือ เดาความหมายไม่ค่อยได้เลย) คำที่รู้ก็เลยมีน้อยกว่า ... คือ ได้ประมาณเนี้ย

eingang = ทางเข้า
ausgang = ทางออก
toiletten = ส้วม
fahrkarten = ตั๋ว
bahnhof = สถานีรถราง/รถไฟ
haupt = หลัก (head, main)
platz = place
markt = market

โรงแรมที่พัก ชื่อว่า Winter's Eurotel Boardinghouse อยู่ในเมือง Offenbach ที่ไม่ได้พักใน Frankfurt ก็เพราะว่าจองโรงแรมใน Frankfurt ไม่ทัน มันเต็มหมดเลย (หรือไม่ก็แพงสุด ๆ) ที่นี่ มีอินเทอร์เน็ตแบบไร้สายนะ แต่ว่า ราคายี่สิบสี่ยูโรครึ่ง ต่อ ยี่สิบสี่ชั่วโมง เลยไม่เอา

วันพุธ ตื่นเช้าหน่อย ไปดูงาน Achema 2006 ละ ... ในนี้ ถ่ายรูปไม่ค่อยได้หนะ เลยไม่มีรูปมาโชว์เยอะเท่าไหร่

งานนี้ใหญ่มากเลย สถานที่จัดงานเรียกว่า Messe Frankfurt มี Hall ทั้งหมดสิบ Hall แต่ละ Hall มีขนาดเท่าศูนย์ ฯ สิริกิติ์เลยมั้ง แล้วยังให้เดินได้ Hall ละหลาย ๆ ชั้นด้วย ... เดินยังไงจะครบเนี่ย

ค่าบัตรเข้างาน เค้าคิดคนละยี่สิบสามยูโร งานเปิดวันละเก้าชั่วโมง คือตั้งแต่เก้าโมงเช้า ถึงหกโมงเย็น ดังนั้น ค่าเข้าชมงาน ถ้าอยู่ตลอดเก้าชั่วโมง ก็ตกเฉลี่ยชั่วโมงละ 2.56 ยูโร (ประมาณนาทีละสองบาท)

ของกินในงานเนี่ย แย่จัง ... มีแค่ขนมปังกะไส้กรอก แล้วก็ไอติมเนสท์เล่ ราคาแต่ละอย่าง ไม่สมกับปริมาณเลย ไส้กรอกหนึ่งเส้นกับขนมปังห่วย ๆ หนึ่งก้อน ราคาสองยูโรครึ่ง ไอตินเนสท์เล่สองลูกเล็ก ๆ (เน้นว่าเล็ก ๆ) บนโคนหนึ่งอัน ก็ราคาสองยูโรครึ่ง ส่วนน้ำเปล่ากับน้ำอัดลม ราคาเท่ากันคือแก้วละสองยูโร ตอนแรกต้องมัดจำค่าแก้วใบละครึ่งยูโรด้วย (เอาแก้วไปคืน จะได้เงินคืนมา)

จริง ๆ วัฒนธรรมการมัดจำภาชนะเนี่ย มันก็มีหลายประเทศแล้วแหละ ... น่าแปลกเหมือนกัน ที่อิตาลีเค้าไม่มีแบบนี้

ตอนเย็น พองานปิด ก็เดินไปที่ Frankfurt Hauptbahnhof แล้วขึ้นรถไฟสาย S9 ไปที่ Offenbach Marktplatz กะจะหาของกิน ที่ไหนได้ เค้าปิดกันเกือบหมดแล้ว ... เหลือ KFC เปิดอยู่ ไปกินก็ได้ - -''

วันพฤหัสก็ ไปดูงานอีกวัน ไม่มีไรมากหรอก ก็อยู่ในงานทั้งวัน ตอนเย็นก็ไปหาของกิน แต่คราวนี้ ไม่ได้ไป KFC ละ เพราะว่าออกจากงานก่อนเวลาปิดนิดนึง ร้านอาหารอื่นเค้ายังไม่ปิด วันนี้ไปกินขาหมูเยอรมันที่ร้าน ... ลืมชื่อไปแล้ว :P

วันศุกร์ ไปเที่ยวละ คราวนี้ เริ่มเดินจาก Frankfurt Hauptbahnhof ไปยัง Hauptwache แถวนี้ร้านขายของเยอะมากเลย มี Department Store แปดชั้นด้วย ... ของที่ขายก็เหมือน ๆ ร้านในกรุงเทพ ฯ นี่แหละ ... ที่ต่างจากห้างของเมืองเราก็มีบันไดเลื่อนนี่แหละ ... ชั้นนึงมันต่อกับบันไดเลื่อนแปดอันหนะ สะดวกดี ... (ถ้าไม่เข้าใจ รอดูภาพละกัน)

อยากจะซื้อของกลับไปฝากหลาย ๆ อย่างนะ แต่มันมีแต่ช็อกโกแล็ตอะ - -''

วันเสาร์แล้ว วันนี้จะกลับละ แต่ขอไปซื้อของฝากอีกนิดนึงก่อน ... เครื่องบินเค้าเรียกเข้าตอนบ่ายสองสิบห้านาที บังเอิญว่าไปถึงสนามบินแต่เช้า ก็เลยมีเวลาเดินหาของนานหน่อย ... แย่จัง มีเวลาเยอะ แต่ของมันดันมีน้อย ... ไป ๆ มา ๆ ก็มีแต่ช็อกโกแล็ตอะ

บ่ายสามนิด ๆ เครื่องบินก็เริ่มปลดเปลื้อง ... บนเครื่องบินคราวนี้ ฉายหนังสองเรื่อง เรื่องแรกคือ Prime อีกเรื่องคือ King Kong

... หมดละ ถึงกรุงเทพ ฯ ซะที!

Monday, May 08, 2006

วันนี้ก็ยาวอีกแล้ว

ตื่นตอนเช้า กินอาหารเช้า แต่งตัว ... พอถึงเก้าโมงก็มีคนมารับไปโรงงาน

ถ่ายรูปโรงงานเค้าได้ซักสิบกว่า ๆ รูป กล้องดันแบตหมด - -'' ... ช่างมัน พรุ่งนี้ค่อยไปถ่ายใหม่ละกัน (จริง ๆ แบตมันก็อยู่ใกล้ ๆ แหละ แต่ไม่มีโอกาสไปหยิบ)

ในโรงงานเค้ามีตู้ขายกาแฟร้อนด้วย หยอดได้แต่เหรียญนะ ... ใกล้ ๆ ตู้ก็มีป้ายห้ามสูบบุหรี่ (ถ้าสูบ จะถูกปรับตั้งแต่ 28.5 ถึง 285 ยูโร) แต่คนงานเค้ามาสูบตรงนี้เพียบเลย ... ก็มันสูบกันทุกคนหนิเนอะ

พอบ่ายโมง เค้าก็พาไปกินข้าวกลางวัน เป็นโรงอาหารของโรงงานแหละ แต่อาหารก็พอใช้ได้นะ ... (ดีกว่าข้าวกลางวันของสาธิตจุฬาฯ ฝ่ายประถม แน่ ๆ)

ประมาณบ่ายสอง ก็กลับไปฟังเค้าบรรยายเรื่องเครื่องมือ เอา drawing มาให้ดูเพียบเลย ... เริ่มรู้สึกว่าตัวเองกะเหรี่ยงแฮะ ไม่รู้จักเครื่องหมายเค้าเลย (แต่พอฟัง ๆ แล้วก็เริ่มจะเข้าใจบ้างหละ)

ก่อนจะไปกินข้าวเย็น เรื่องสุดท้ายที่เค้าบรรยายก็คือ Plasma Sterilizer ซึ่งผู้ผลิตรายที่ดังที่สุดคือ Johnson & Johnson ทำอยู่เจ้าเดียวมาสิบปีแล้ว เพิ่งจะมีคนอื่นเริ่มทำก็ปีที่แล้วเนี่ยแหละ การทำงานของมันก็เข้าใจไม่ยากนะ แต่ทำยากจัง เค้าบอกว่า ต้องใช้ High Vacuum Pump เพื่อทำความดันภายใน chamber ให้ได้ต่ำถึง 0.01 millibar สัมบูรณ์ จากนั้นก็พยายามทำให้อิเล็กตรอน หลุดออกจากโมเลกุลของอากาศที่ยังเหลืออยู่ โมเลกุลมันก็จะไวต่อสนามไฟฟ้าเพราะมันมีประจุ ส่วนอิเล็กตรอนที่หลุดออกไป มันก็ไวเหมือนกัน พอของพวกนี้วิ่งไปชนกับสารอินทรีย์ พันธะมันก็จะแตกออกง่าย ๆ เค้าก็เลยใช้วิธีนี้ฆ่าเชื้อ ... เพื่อจะทำให้อิเล็กตรอนมันหลุดง่าย ๆ เค้าก็ใส่ก๊าซที่มีความเสถียรต่ำ เพิ่มลงไปด้วย (อันนี้เค้าใช้ H2O2)

ข้อดีของวิธีนี้ก็คือ ใช้อุณหภูมิต่ำ คือ ประมาณ 40 - 55 °C เท่านั้น เลยใช้กับพลาสติกหรือวัสดุไม่ทนความร้อนได้ แต่ข้อเสียก็คือ ของที่ใส่เข้าไปต้องแห้งจัด ๆ

ความรู้ที่ได้เพิ่มตรงนี้มีสองเรื่อง คือ
  1. เหตุผลที่ต้องให้ของของเรา แห้งจัด ๆ ก็เพราะว่า ที่ความดัน 0.01 mbar สัมบูรณ์เนี่ย จุดเดือดของน้ำจะต่ำมาก (เกือบ 0°C) น้ำทั้งหมดจะกลายเป็นไอ ทำให้ปริมาณก๊าซใน chamber เพิ่มขึ้น ซึ่งก็แปลว่า ความดันจะเพิ่มด้วย มันก็จะไม่ใช่ 0.01 mbar แล้ว ตัว vacuum pump ต้องดูดเอาพวกนี้ออกให้หมดด้วย กระบวนการแบบนี้จะกินแรง pump มาก ๆ บางครั้งเครื่องอาจจะหยุดทำงานไปเลย แล้วแจ้งเตือนว่าความชื้นสูงเกินไป
  2. สถานะของก๊าซที่มีประจุเนี่ย เรียกว่า plasma (กะเหรี่ยงมั้ยเนี่ย ไม่รู้มาก่อน :P)
ถึงตอนเย็นเค้าก็พาไปกินข้าวเย็น จะบอกว่า สองทุ่มแล้วแหละ แต่ฟ้ายังไม่มืดเลยนะ

ที่ร้านอาหาร เค้าก็สอนภาษาอิตาลีให้นิด ๆ หน่อย ๆ เอาสนุก ส่วนใหญ่คือ จะแปลเมนูภาษาอิตาลีให้ฟัง (ร้านนี้ไม่มีเมนูภาษาอังกฤษ) จำได้นิดเดียวเอง ประมาณเนี้ย ...

acqua = water
antipasto = appetizer
zucchero = sugar

salmone = salmon
melone = melon
limone = lemon

fritto = fried
misto = mixed

mare = sea
pesce = fish
pescatore = fisherman
calamari = squid(s)
patata = potato
funghi = mushroom(s)

อ้อ ... แล้วก็ calcium เนี่ย เค้าอ่านว่า "คัลชุ่ม" แหละ

กินเสร็จก็กลับโรงแรมเลย ... ตอนนี้ก็ เลยเที่ยงคืนแล้วอ่า ... ไปนอนละ

Sunday, May 07, 2006

วันนี้ยาวจัง

กะจะเอารูปมาให้ดูด้วย แต่ว่าลืมเอาสายต่อกล้องมา เลยเอาลงเครื่องคอมพ์ไม่ได้ T_T เล่าให้ฟังเป็นตัวอักษรอย่างเดียวก่อนละกัน

ประมาณเที่ยงคืนครึ่ง วันนี้ ขึ้นเครื่องบิน สายการบินไทย ประตูยี่สิบสี่ ปลายทาง กรุงโรมนะครับ นั่งรอจนเที่ยงคืนห้าสิบห้า เครื่องบินก็เริ่มเปลื้องผ้า (Take Off)

ตอนแรก บนจอทีวี เปิดซีรีส์ซิทคอมเรื่อง ... จำชื่อเรื่องไม่ได้อะ ... ก็ฮาใช้ได้ รายการต่อจากนั้นก็เป็น ดนตรีคลาสสิก ไม่สิ ดนตรีบาโรค มาพร้อมกับอาหารมื้อตีหนึ่งกว่า ๆ พอกินกันเสร็จ ผู้คนก็เริ่มหลับกัน (สงสัยเพราะเพลงน่ะแหละ) ... เรายังไม่อยากนอน ก็เลยนั่งวาดรูปเล่น (รูปเรขาคณิตหนะ กำลังคิดเรื่องที่ทำวิจัยอยู่ ... คิดไปคิดมา ได้ความว่า มันยากกว่าที่เคยคิดแฮะ) ผ่านไปประมาณชั่วโมงนึง เริ่มง่วง ๆ เลยนอนมั่ง

ตื่นมา เค้าเปิด Narnia ให้ดูด้วย ... ดูแล้วก็เลยรู้ ว่าทำไมคนถึงด่ากันจัง ... ดูจบ กินข้าว รออีกแป๊บนึงก็หกโมงเช้าสามสิบห้านาที ถึงเวลาเครื่องบินแตะพื้นกรุงโรมละ

ตรงที่ตรวจหนังสือเดินทางเนี่ย คนแน่นมากกกก ... กว่าจะออกจากสนามบินได้ ประมาณชั่วโมงนึงแหนะ ... จะบอกว่า ห้องน้ำในสนามบิน Fiumicino เนี่ย แย่กว่าดอนเมืองพอควรเลย

ออกมา ก็มีคนขับรถมารับ ... รู้สึกไม่ค่อยคุ้นเคยกับรถชิดขวาเลยแฮะ ... นั่งรถประมาณครึ่งชั่วโมงก็ถึงโรงแรม Hotel Centrale ใน Pomezia

เนื่องจาก Pomezia เป็นย่านอุตสาหกรรม ก็เลยไม่มีที่ท่องเที่ยวให้ดูเลย ... แต่ที่แย่กว่านั้น วันนี้วันอาทิตย์ครับ ... เมืองหยั่งกะเมืองร้างแหนะ มีแต่ตึก ไม่มีคน ไม่มีร้านขายของ ... จริง ๆ มีอยู่ร้านนึงใกล้ ๆ โรงแรม แต่ว่ามันปิดวันอาทิตย์หนะ

ส่วน ตัวโรงแรม Hotel Centrale เนี่ย ก็ไม่ใช่โรงแรมหรูหราอะไรเลย ไว้หาสายต่อกับกล้องได้แล้วจะเอารูปให้ดู ลิฟท์ยังมีแบบที่กดปุ่มแล้วไฟไม่ขึ้น ข้างในก็ไม่มีจอบอกว่าอยู่ชั้นไหนแล้ว ...

แต่สิ่งแปลก ๆ เท่ ๆ ก็มีอยู่บ้างนะ คือ ลิฟท์เค้า มีชั้น 0 กับ -1 ด้วยอะ ... เขียนหยั่งงี้บนปุ่มให้กดเลยนะ

แล้วก็ ในห้องพักสำหรับสองคนเนี่ย ... ประตูห้องน้ำไม่มีล็อก

และที่ขาดไม่ได้ ... มันมี Internet ให้ใช้ด้วย !!! มีได้ไงไม่รู้

ตอนนี้ก็ ... สี่โมงยี่สิบสามละ (เหลือบไปเห็นนาฬิกาของเครื่องคอมพ์ ... 9:38 PM แล้วนี่หว่า) พอดีกว่า ไปคุย msn ละ ไว้มีอะไรจะมาบอกเรื่อย ๆ นะ

Tuesday, May 02, 2006

กำลังจะไปยุโรป

วันที่ 6 - 20 เดือนนี้ จะไป Rome กับ Frankfurt หละ ไว้จะถ่ายรูปมาให้ดูกันบ้าง ... (กลับมา จะ update ละ)

Thursday, April 13, 2006

สวัสดีปีใหม่ไทย

สุขสันต์วันสงกรานต์จ้าาาา!!!

อยู่เชียงใหม่หละ เล่นน้ำที่คูเมือง หนุกดี

Sunday, February 05, 2006

คนชอบ คนไม่ชอบ ...

คนที่ชอบเรา = คนที่พอใจในสิ่งที่เราทำ
คนที่ไม่ชอบเรา = คนที่ไม่พอใจในสิ่งที่เราทำ
คนที่รู้สึกเฉย ๆ กับเรา = คนที่ไม่คิดว่าต้องสนใจการกระทำของเรา

ระดับความพอใจที่ X รู้สึกต่อ Y
  • ความพอใจจากประสบการณ์ตรง: Y ช่วย X
  • ความพอใจจากการวิเคราะห์: X รู้สึกว่า Y ทำสิ่งที่ X เห็นว่าดี
คำว่า "ช่วย" เอง ก็มีหลายลักษณะ เช่น
  • เป็นที่พี่งทางใจ
  • ช่วยแก้ปัญหา
  • ให้เงิน
  • ซ่อมถนนแถวบ้าน
  • พัฒนาชุมชนแถบใกล้เคียง
  • ฯลฯ
ส่วน "ข้อมูลที่ทำให้พอใจ" จากการวิเคราะห์ ก็มีหลายแบบ เช่น
  • ทำให้คนทั้งโลกมีความสุขมากขึ้น
  • ทำให้คนหลาย ๆ คน รวยขึ้น
  • ทำให้คนที่เราไม่ชอบ เสียหาย
  • ปราบยาเสพติดได้
  • สร้างงานให้ชนชั้นล่าง
  • ทำให้เศรษฐกิจดีขึ้น
  • ฯลฯ
อย่างไรก็ตาม ข้อมูลที่ทำให้พอใจ มีความเป็นไปได้ว่าจะเป็นข้อมูลเท็จ สูงกว่าประสบการณ์ตรง นอกจากนั้น ข้อมูลเดียวกัน อาจให้ผลการวิเคราะห์ที่แตกต่างกัน สำหรับแต่ละบุคคล กล่าวคือ บางคนอาจจะพอใจ แต่บางคนอาจจะไม่พอใจ เมื่อได้รับข้อมูลเดียวกัน

ความพอใจของคนหมู่มาก

มันเป็นเรื่องปกติที่ เราไม่สามารถสร้างประสบการณ์ตรงกับคนหมู่มาก (เช่น ทั้งประเทศ) ได้ วิธีที่จะทำให้คนส่วนใหญ่พอใจเรา ก็คือ การให้ข้อมูล

เพื่อที่จะให้ข้อมูลด้านดีของเรา ไปถึงคนส่วนใหญ่ได้ เราก็ควรจะควบคุมสื่อของข้อมูล ที่เข้าถึงคนส่วนใหญ่ได้ (เช่น โทรทัศน์ วิทยุ หนังสือพิมพ์ ฯลฯ)

วิธีควบคุมสื่อที่เข้าถึงคนส่วนใหญ่ได้ ก็มีมากมายหลายอย่าง เช่น
  • เป็นเจ้าของสื่อเอง
  • ควบคุมสื่ออื่นทางตรง (ซื้อ)
  • ควบคุมผู้ที่ทำงานให้สื่ออื่น
วิธีการ "ควบคุมคน" สามารถทำได้ง่ายกว่าการทำให้คนกลุ่มใหญ่พอใจ ดังนั้น แนวทางหนึ่งในการทำให้คนพอใจ ก็คือ

ใช้คนที่เราควบคุมได้ ไปเผยแพร่ข้อมูล (ที่อาจจะไม่จริง) เพื่อให้คนกลุ่มใหญ่พอใจ

ข้อมูลดึงอารมณ์

วิธีการสร้างข้อมูลสนับสนุนหรือบ่อนทำลาย มักจะเน้นที่การดึงอารมณ์ ตัวอย่างการสร้างภาพขอความเห็นใจ เช่น
  • กลุ่มคนที่บ้าคลั่ง กำลังด่าทอ สาปแช่งเรา
  • เด็ก คนแก่ คนป่วย คนพิการ คนจน มาให้กำลังใจเรา
หน้าที่ของผู้วิเคราะห์ที่ดีก็คือ ควรจะควบคุมไม่ให้อารมณ์มาเหนือเหตุผล และคิดเผื่อความเป็นไปได้ในหลาย ๆ ทาง เช่น กลุ่มคนดังกล่าว (ในตัวอย่างภาพที่สร้าง) มีความเป็นไปได้ที่จะถูกว่าจ้าง สูงกว่าคนปกติ

ประชาธิปไตย

ประเด็นสำคัญของประชาธิปไตยก็คือ จำนวนคนที่ชอบเรา ดังนั้น วิธีที่กล่าวไว้ จึงเป็นวิธีที่นักการเมือง ในประเทศประชาธิปไตย นิยมมากที่สุด

แล้ว สิ่งที่ประชาชนควรกระทำหละ?

โดยอุดมคติแล้ว หน้าที่ของประชาชนก็คือ วิเคราะห์ประสบการณ์และข้อมูลต่าง ๆ แล้วตัดสินใจ เพื่อผลประโยชน์สูงสุดของประเทศชาติ

แต่ ถ้าทุกคนคิด "ถูกต้องที่สุด" เหมือนกัน (และสิ่งที่ถูกต้องที่สุดมีเพียงหนึ่งเดียว) การเลือกตั้งทุกครั้งก็คงจบลงที่ มีผู้สมัครรับเลือกตั้งเพียงผู้เดียวเท่านั้นที่ได้คะแนนไม่เป็นศูนย์

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

สรุปก็คือ เราควรจะถามตัวเองเสมอ ๆ ด้วยเหตุผล เพื่อเตือนตัวเองให้ตัดสินใจใกล้เคียง "อุดมคติ" มากที่สุด ตัวอย่างคำถามก็เช่น
  • ถ้าเราพอใจ X จากประสบการณ์จริง แสดงว่า X ทำเช่นเดียวกันกับผู้อื่นหรือไม่?
  • ถ้าเราพอใจ X จากประสบการณ์จริง ผู้อื่นจะพอใจกับประสบการณ์แบบเดียวกันหรือไม่?
  • ข้อมูลเกี่ยวกับ X ที่เราได้รับ มีโอกาสเป็นจริงหรือเท็จมากแค่ไหน?
  • เรามีอคติหรือไม่ ในการวิเคราะห์ข้อมูลเกี่ยวกับ X?
  • ถ้าเราพอใจข้อมูลที่ได้รับเกี่ยวกับ X ผู้อื่นจะพอใจข้อมูลเดียวกันนี้หรือไม่?
  • ฯลฯ
ประเด็นที่สำคัญอีกเรื่อง ก็คือ เมื่อเราตัดสินใจไปแล้ว เราก็ไม่จำเป็นต้องยึดติดกับความคิดเก่านั้น เมื่อเราได้รับประสบการณ์หรือข้อมูลเพิ่ม เราก็ควรจะวิเคราะห์ใหม่ เพื่อให้แนวทางประชาธิปไตย สมบูรณ์แบบยิ่งขึ้น

ผู้สนับสนุนส่วนเกิน

คนที่เชี่ยวชาญเรื่องเกี่ยวกับ Y มักจะไม่ยอมรับ X เมื่อ X เป็นอะไรซักอย่างใน Y

(ที่ใช้คำว่า "มักจะ" ก็เพราะว่า มันไม่ใช่ทุกครั้ง)

ตัวอย่างเช่น
  • คนที่ดูหนังมามาก ๆ มักจะวิจารณ์หนังเรื่องใหม่ ๆ ในทางลบ
  • คนที่เห็นเสื้อบอลมามาก ๆ จะไม่ชอบเสื้อบอลรุ่นใหม่
  • ฯลฯ
สาเหตุที่เป็นอย่างนี้ ก็อาจจะเป็นเพราะ ผู้ที่เชี่ยวชาญเรื่องเกี่ยวกับ Y มักจะเคยรู้จักสิ่งที่ดีกว่า X หรือถ้าผู้นั้นเคยทำสิ่งที่เกี่ยวกับ Y เองโดยตรง ก็อาจจะไม่อยากยอมรับคนที่เก่งกว่า

(อย่างไรก็ตาม การไม่ยอมรับ ไม่ใช่สิ่งที่ผิด)

เรื่องที่น่าแปลกก็คือ ข้อความตรงข้ามของประโยคข้างบน ก็เป็นจริงค่อนข้างบ่อย

คนที่ไม่เชี่ยวชาญเรื่องเกี่ยวกับ Y มักจะยอมรับ X เมื่อ X เป็นอะไรซักอย่างใน Y

เหตุผลที่เป็นเช่นนี้ ก็อาจจะเป็นเพราะว่า โดยธรรมชาติของมนุษย์ ไม่ชอบความขัดแย้ง ดังนั้น เมื่อมีใครเสนออะไรขึ้นมา เราก็มักจะไม่อยากไปโต้แย้งเขา นอกจากเราจะรู้จริง ๆ ว่ามันไม่ดีอย่างไร (คือ เราเชี่ยวชาญเรื่อง Y หรืออย่างน้อย เราคิดว่าเราเชี่ยวชาญเรื่อง Y)

(การยอมรับ ก็ไม่ใช่สิ่งที่ผิด)

ผลลัพธ์อย่างนึงของประโยคนี้ก็คือ คนที่ไม่ได้ใส่ใจการเมือง มีแนวโน้มจะยอมรับรัฐบาล

เมื่อผนวกกับ ความกลัวความเปลี่ยนแปลง ซึ่งเป็นธรรมชาติของมนุษย์อีกอย่าง เราจึงรู้ว่า

คนที่ไม่ได้ใส่ใจในการเมือง มีแนวโน้มที่จะยอมรับรัฐบาล และไม่คิดล้มล้างรัฐบาล

คนเหล่านี้ เป็น "ผู้สนับสนุนส่วนเกิน" ของรัฐบาล

รัฐบาลที่ฉลาด จะเห็นช่องว่างตรงนี้ แล้วพยายามดึงคนกลุ่มนี้เป็นพวกให้มากที่สุด เพราะว่า มีปริมาณมาก และคล้อยตามง่าย

อย่างไรก็ตาม ผู้สนับสนุนส่วนเกิน ไม่ใช่ผู้ที่ขัดขวางแนวทางของประชาธิปไตย แต่เป็นส่วนประกอบที่เกิดขึ้นจาก ธรรมชาติของประชาธิปไตย

คนเดินขบวน

คนส่วนใหญ่ มักจะมีหน้าที่ประจำของตัวเองอยู่แล้ว การที่จะต้องละทิ้งหน้าที่ตัวเองเพื่อไปทำอะไรซักอย่าง ที่มัน "ไม่ปกติ" แสดงว่าสิ่งที่ไปทำนั้น จะต้องสำคัญมาก ๆ รัฐบาลควรมองพวกที่เดินขบวนเป็นข้อมูลที่ต้องสนใจ

การตั้งตัวเป็นศัตรูกับพวกที่เดินขบวน แล้วไม่รับฟังสิ่งใด ๆ จากคนเหล่านี้ ถือว่าเป็นสิ่งที่ไม่สมควรกระทำ รัฐบาลใด ๆ ควรจะเข้าใจว่า ปกติแล้ว คนจะไม่พยายามมาเหนื่อยในเรื่องแบบนี้ ถ้ามีขบวนเกิดขึ้น รัฐบาลควรจะถามว่า เขามาเดินขบวนกันทำไม จะได้ไปแก้ปัญหาให้ได้

การสลายกลุ่มผู้ประท้วง โดยการจ้างกลุ่มคนก่อความไม่สงบ (เช่น จ้างหญิงโสเภณีมาตีคนแก่ จ้างชาวบ้านมาแสดงการเผารูปผู้นำกลุ่มเดินขบวน ฯลฯ) เป็นสิ่งที่เลวร้ายยิ่งกว่าการไม่ฟังยิ่งนัก

อย่างไรก็ตาม กลุ่มผู้ประท้วง หรือกลุ่มคนก่อความไม่สงบ อาจจะถูกว่าจ้างมาจากฝั่งใดก็ได้ เช่น กลุ่มผู้ประท้วง อาจจะถูกว่าจ้างโดยฝ่ายค้าน หรือกลุ่มคนก่อความไม่สงบ อาจจะถูกว่าจ้างโดยกลุ่มผู้ประท้วงเอง เพื่อสร้างภาพที่ไม่ดีต่อรัฐบาล ดังนั้น เป็นหน้าที่ของคนทุกคนที่ได้รับข้อมูลเหล่านี้ ที่จะต้องวิเคราะห์ด้วยเหตุผล อย่าคล้อยตามไปกับปริมาณข้อมูล

ถึงแม้ประชาธิปไตยจะเน้นสิทธิความเท่าเทียมกันของบุคคล แต่ตัวตนของผู้เดินขบวนก็เป็นข้อมูลที่ไม่ควรละเลย โดยเฉพาะ ในกรณีที่ผู้เดินขบวน เป็นคนมีอายุ มีฐานะการงาน มีครอบครัว สิ่งนี้แสดงว่า ถึงแม้จะมีภาระรับผิดชอบมากมาย ยังยอม "เสี่ยงชีวิต" มาเดินขบวน

ตัวอย่างเช่น ผู้เคยที่ประท้วงรัฐบาลในอดีต (เมื่อยังเป็นนักศึกษา) มีแนวโน้มที่จะเป็นผู้เชี่ยวชาญการเมือง สูงกว่าคนทั่วไป และมีแนวโน้มที่จะ "รักชาติ" มากกว่าด้วย การเรียกผู้มีอายุเหล่านี้ว่าเป็น "นักธุรกิจที่ถูกขัดผลประโยชน์" จึงฟังดูไม่สมเหตุสมผล (ในทางอุดมคติ ไม่ควรจะมี "นักธุรกิจที่ถูกขัดผลประโยชน์" ด้วยซ้ำ)

Sunday, January 29, 2006

ฮา...

อ่านอันข้างล่างแล้วหมั่นไส้ตัวเองแฮะ

Saturday, January 28, 2006

เกือบโกหก ... ?

ประเด็นมันอยู่ที่ว่า หลาย ๆ คน คิดว่า คนที่จะเข้าวิศวะจุฬา ฯ ได้เนี่ย จะต้องขยันเรียนสุด ๆ (อย่างน้อยก็ ตอน ม. ปลาย) และคนที่จะได้เกียรตินิยมอันดับ 1 เนี่ย มันต้องขยันโคตร ๆ ๆ ๆ

เรื่อง 2 เรื่องต่อไปนี้ เป็นเหตุการณ์ตัวอย่าง (จริง ๆ มีมากกว่า 2 ครั้ง) ซึ่งอาจจะไม่ได้ตรงกับเหตุการณ์จริง 100% นะ

เรื่องที่ 1

เพื่อนผมคนนึง เคยเป็นอันดับต้น ๆ ของโรงเรียนตอนมัธยม เค้าอยู่วิศวะจุฬา ฯ เหมือนกัน (ตอนนั้นยังเรียนอยู่) แต่เกรดเค้าไม่ค่อยดี (คือ ใกล้ ๆ 3 ... บางคนก็บอกว่าดีแล้ว) พอไปคุยกะแม่เค้า แม่เค้าถามเกรดผม ... พอบอกไปปุ๊บ (ตอนนั้น 3.85) ก็ได้คำพูดตอบกลับมาทันทีว่า

อ่านหนังสือทบทวนทุกวันเลยสิ ดูอย่างเพื่อนไว้บ้างนะ

ฮ่วย ... พูดไม่ออก ... เพื่อนผมก็พูดไม่ออกด้วยอะ ก็เค้ารู้แหละ ว่าผมเป็นไง ให้เอาอย่างผมก็ยิ่งซวยสิ ... สุดท้ายก็ได้แค่ ผงกหัวแล้วพูด "ครับ ๆ" อย่างเดียว

เรื่องที่ 2

มีแม่ของเด็กม.ปลายคนนึง (คือ เค้ารู้จักกับญาติผมหละ) ถามว่า

อยู่วิศวะจุฬา ฯ ได้เนี่ย ต้องขยันมาก ๆ เลยสิ

จะให้ปฏิเสธหรอ? ... คือ ในใจก็รู้ตัวว่า ไม่เคยขยันเรียนอย่างที่คนอื่น ๆ เค้าพูดกัน แต่ไงดีหละ ... ก็เอาเป็นว่า สิ่งที่เราทำ ๆ ไป คนอื่นคงเรียกได้ว่า "ขยันมาก ๆ" หละมั้ง

เลยตอบแบบคลุมเครือไป ประมาณว่า

ครับ ตอนเอ็นทรานซ์เนี่ย ก็ต้องดูหนังสือเยอะ

ในใจก็แอบคิดว่า ไอ้คำว่า "เยอะ" เนี่ย ... มันไม่มีนิยามที่เฉพาะเจาะจง คงไม่เรียกว่าโกหกนะ ... แต่แล้ว เค้าก็ถามต่อมาว่า

ดูหนังสือก่อนสอบกี่เดือนหละ?

เวรกรรม ... จะตอบว่าสัปดาห์เดียวได้มั้ยหละเนี่ย ... ขอเลี่ยง ๆ อีกหน่อยละกันนะ

ก็ ... เตรียมตัวสอบเกือบทั้งปีหละครับ

"เตรียมตัวสอบ" เนี่ย คิดในใจว่า รวมเรื่องสมัครสอบไปด้วยละกัน คิดว่า ตั้งแต่เตรียมตัวสอบครั้งแรก ถึงการสอบครั้งที่สอง มันคงเรียกว่า "เกือบทั้งปี" ได้มั้ง ...

ยัง ยัง ... ยังไม่รอด ...

แล้วดูหนังสือวิชาเลขยังไงหรอ?

แป่วววว ... เล่นบอกวิชามางี้ ... ไม่ได้ดูอะ ... อ้อ ๆ แต่ ที่โรงเรียนมีโจทย์ (การบ้านงี่เง่า ๆ หนะ) ให้ทำเรื่อย ๆ หนิ

ก็ทำโจทย์เยอะ ๆ หละครับ

ตอนนี้ ในใจก็คิดว่า แค่มากกว่า 0 คงเรียกว่า "เยอะ ๆ" ได้มั้ง ... แต่มันเริ่มขัดกับอุดมการณ์ตัวเองแล้วอะ ไม่เคยคิดเลย ว่าจะบอกให้คนอื่นท่องรูปแบบโจทย์ แต่เค้าต้องคิดงั้นแน่เลย และแล้ว เค้าก็บอกว่า

เห็นมั้ยลูก ทำโจทย์เยอะ ๆ นะ เอาให้ครบทุกแบบเลย

- -'' ... ซะงั้น ... นี่มันเรียนผิดวิธีเลยนะ ...

Monday, January 16, 2006

งาน TAM 2006

ไปมาเมื่อวันเสาร์ จะบอกว่า
TAM 2006 ห่วยแตก!!
ไม่มีอะไรน่าสนใจเลยอะ

Sunday, January 08, 2006

อาวละ ... สรุป blog

blog ที่เกิดใหม่ตอนปีใหม่ มีดังนี้...

Another Tunoblog - blog เรื่องไร้สาระ

Tunology - blog วิชาการ
(ใครที่อ่านสิ่งที่เคยเขียนไว้ที่นี่ (Tunoblog) ไม่ค่อยรู้เรื่อง ลองไปดูใหม่ที่ Tunology นะ อาจจะรู้เรื่องมากขึ้น)

Tunosong - blog เกี่ยวกะดนตรี

แต่ยังไม่เลิกเขียนอันนี้นะ แค่จะ update น้อยลง (เยอะเลย)

อัตราการ update ของทุก blog รวมกัน ก็คงจะน้อยกว่า blog นี้ในอดีตอยู่ดี :P

Wednesday, January 04, 2006

ไปเล่นมาเพียบเลย ...

จะย้ายเรื่องวิชาการไปที่ Tunology แล้วนะ ส่วน Tunoblog อันนี้ ก็คงจะซีเรียสน้อยลงละ

Another Tunoblog เขียนเป็นภาษาอังกฤษนะ

แล้วก็ เรื่องดนตรี กับเพลงที่เอาให้ฟัง จะย้ายไปอยู่ที่ Tunosong หละ

ของ blogsource ไม่เอาแล้ว ห่วยกว่า blogger อะ ...

แล้วอยู่ดี ๆ ใจ๋ก็มาบอกว่า ให้ไปทำที่ multiply.com ... มันมีเนื้อที่ไม่จำกัดอะ ...

ย้ายอีกทีดีมั้ยเนี่ย

Sunday, January 01, 2006

สวัสดีปีใหม่ครับ

สวัสดี .. ปี .. ใหม่แล้ว .... ผองไทย .. จงแคล้ว .. ปวงภัย .... นะ

Wednesday, December 28, 2005

ไปเล่นมา ...


ตามกระแสเก่านิด ๆ ... เขียนภาษาอังกฤษมั่ง

Tuesday, December 27, 2005

ม่ายหวายแล้ววววววว!!!

เขียนบ่อย ๆ ไม่ไหวแล้วอะ ... งานมหาศาล ... หยั่งงี้ยังเรียกว่าว่างงานได้มั้ยเนี่ย

แต่ยังไม่เลิกเขียนนะ!

Monday, November 21, 2005

ถึงคราวต้องสร้าง Virtual Machine แล้ว (พื้นฐาน)

เพื่อให้เห็นภาพ ว่าที่ผ่าน ๆ มา มันเป็นอะไร คราวนี้ มาลองสร้าง Virtual Machine กันเถอะ ... มาสรุปสิ่งที่ Virtual Machine ควรจะมีก่อน ... ครั้งนี้คิดสำหรับ process เดียวก่อนนะ

Memory Units

เพื่อให้สามารถสร้าง memory module ได้ เราต้องกำหนดไว้ก่อนว่า แต่ละ word มีขนาดเท่าไหร่ ... สมมติเลยละกันนะ ว่า

ตำแหน่งของ memory 1 ตำแหน่ง จะเก็บข้อมูลได้ 1 byte
ขนาดของ instruction = 4 byte

Process Space
  • PC - Program Counter
  • Memory - แบ่งเป็น
    • Stack
      • SP - Stack Pointer
      • BP - Base Pointer
    • Heap
  • MA - Memory Address
  • AC - Accumulator
  • FP - Frame Pointer
และ operation ที่เกี่ยวกับ memory พื้นฐาน ก็คือ
  • load: AC ← mem[MA]
  • store: mem[MA] ← AC
  • push X: SP ← SP - 4; mem[SP] ← X
  • pop X: X ← mem[SP]; SP ← SP + 4
Instruction Set

ก่อนอื่น ตกลงกันก่อนว่า ส่วนของ OPCODE เราจะยังไม่ใส่ตัวเลขลงไป แต่สมมติว่ามันกินเนื้อที่ 4 byte (เพื่อให้ง่ายเวลา implement จริงเป็นวงจรด้วย) instruction set ที่เราต้องทำ มีสามกลุ่ม คือ

Fundamental Instructions

PUSH X
  • คำสั่งนี้ พิเศษกว่าคำสั่งอื่นตรงที่มันมี operand ด้วย ... ดังนั้น ขนาดของคำสั่งนี้จะต้องรวม X ลงไปด้วย ... เราจะกำหนดให้ 4 byte แรกเป็น opcode และ 4 byte หลังคือ X รวมกันเป็น 8 byte ต่อการ PUSH 1 ครั้ง
  • การทำงาน: push X
PBASE
  • การทำงาน: push BP
LOAD
  • การทำงาน: pop MA; load; push AC
STORE
  • การทำงาน: pop AC; pop MA; store
JMP
  • การทำงาน: pop PC
JPOS
  • การทำงาน: pop AC; if AC > 0, pop PC, else pop AC
JNEG
  • การทำงาน: pop AC; if AC < 0, pop PC, else pop AC
JZ
  • การทำงาน: pop AC; if AC = 0, pop PC, else pop AC
JNZ
  • การทำงาน: pop AC; if AC ≠ 0, pop PC, else pop AC
CALL
  • การทำงาน: pop AC; push PC + 4; push BP; BP ← SP; PC ← AC
RETURN
  • การทำงาน: pop AC; SP ← BP; pop BP; pop PC; push AC
Dynamic Allocation Instructions

คำสั่งในกลุ่มนี้มีสองคำสั่งคือ ALLOC กับ FREE การทำงานของมันจะพิเศษหน่อย เพราะมันเป็น OS-Level Instruction ดังนั้น จะไม่สามารถ implement เป็น hardware ได้ตรง ๆ

ALLOC
  • การทำงาน: pop AC; AC ← malloc(AC); push AC
FREE
  • การทำงาน: pop AC; free(AC)
Arithmetic and Logical Instructions

พวกนี้ จะมีเยอะเท่าไหร่ก็ได้ ... หลัก ๆ จะมีสองกลุ่มคือ unary กับ binary แต่ถ้าจะทำเพิ่ม ก็ทำได้เรื่อย ๆ นะ

NEG
  • การทำงาน: pop AC; push -AC
ADD
  • การทำงาน: pop MA; pop AC; push AC + MA
SUB
  • การทำงาน: pop MA; pop AC; push AC - MA
MUL
  • การทำงาน: pop MA; pop AC; push AC * MA
DIV
  • การทำงาน: pop MA; pop AC; push AC / MA
MOD
  • การทำงาน: pop MA; pop AC; push AC mod MA
ส่วนคำสั่งที่เป็นด้าน logic เราจะถือว่า 0 = false และ ค่าอื่น ๆ = true นะ (แต่ค่า true ที่เป็น output ของ operation จะกำหนดให้เป็น 1 เลย)

NOT
  • การทำงาน: pop AC; push ¬AC
AND
  • การทำงาน: pop MA; pop AC; push AC ∧ MA
OR
  • การทำงาน: pop MA; pop AC; push AC ∨ MA
IFF
  • การทำงาน: pop MA; pop AC; push AC ↔ MA
XOR
  • การทำงาน: pop MA; pop AC; push ¬(AC ↔ MA)
NAND
  • การทำงาน: pop MA; pop AC; push ¬(AC ∧ MA)
NOR
  • การทำงาน: pop MA; pop AC; push ¬(AC ∨ MA)
แล้วจะมาต่อเรื่อง Floating Point อีกทีนะ

Sunday, November 20, 2005

มาลองทำ Assembler กัน (Process Space)

ลองสมมติว่า เราเขียนโปรแกรมมา คอมไพล์เสร็จ มันเป็นก้อน object code หน้าตาคงที่ ...

คำสั่ง JMP กับ CALL หละ? ตำแหน่งของการกระโดดมันคงที่หนิ ... แสดงว่า ถ้าเราเอา code เราไปวางไว้ที่อื่น (คือ address เริ่มต้นเปลี่ยนไป) มันก็จะทำงานไม่ถูกน่ะสิ!!!

Frame Pointer

ทางแก้ก็คือ แก้ที่ CPU ของเรา ให้ทุกครั้งที่ทำคำสั่งที่เกี่ยวกับ memory ให้เอาเลขที่ได้ ไปบวกกับ FP ก่อน แค่นี้ก็เรียบร้อย ... ว่าแต่ FP นี่มันจะเก็บไว้ที่ไหนหละ? ... ก็กำหนด Register ขึ้นมาอีกตัวสิ

Process Space

ดังนั้น เพื่อให้การทำงานในแต่ละ process ถูกต้อง เราจะเก็บค่า FP ปะติดกับ object code ไว้สำหรับแต่ละ process ... ค่า FP นั้น จะรู้ในเวลาที่ load โปรแกรมลงใน memory

พอถึงเวลาที่ process นั้นจะทำงาน เราก็เพียงแค่ load ค่า FP ของ process นั้นกลับคืนมา การทำงานก็จะถูกต้องแล้ว

Cross-Process Communication

แล้ว เราจะทำให้ process ต่าง ๆ ติดต่อกันได้ยังไงหละ?

วิธีที่เค้านิยมทำกัน จะมีอยู่ 2 แบบคือ
  1. Messaging - ติดต่อผ่าน OS
  2. Shared Memory - ขอ OS ให้เปิดช่องการติดต่อโดยตรง
จริง ๆ ทั้งสองวิธีก็ต้องพึ่ง OS ทั้งคู่ แต่วิธีแรกจะต้องพึ่ง "OS Instruction" มากกว่า

รายละเอียดจริง ๆ ของสองอย่างนี้ จะยังไม่พูดถึงตอนนี้ละกัน ... ไว้หลังจากทำ Virtual Machine กับ Assembler ได้ก่อน

Saturday, November 19, 2005

มาลองทำ Assembler กัน (Return Value)

Return Value Problem

สมมติว่า มี code ภาษา C แบบนี้

 int Succ(int a)
 {
  return a + 1;
 }

พอแปลงเป็นภาษา Assembly จะได้

 Succ:
  REF a -2
  PUSH a
  LOAD
  PUSH 1
  ADD
  RETURN

ไม่มีปัญหา แต่ถ้าในฟังก์ชัน มีตัวแปรภายในอยู่หละ?

 int Double(int a)
 {
  int x = a;
  return a + x;
 }

ลองแปลงเป็น Assembly ดู

 Double:
  REF a -2
 VAR 1
 REF x 1
 PVAR x
 PVAR a
 LOAD
 STORE
 PVAR a
 LOAD
 PVAR x
 LOAD
 ADD
 ???
 ???
  RETURN

ที่ใส่ ??? ไว้ก็คือ เราจะ RETURN เลยไม่ได้ เพราะเรายังไม่ได้เรียก FVAR แต่ถ้าเราเรียก FVAR เนี่ย ค่าที่เราต้องการจะ RETURN มันก็จะหายไป เราจะทำยังไงหละ?

เรารู้ว่า ค่าที่จะถูก RETURN ออกไป จะต้องอยู่ในตำแหน่ง BP - 1 แน่ ๆ ดังนั้น เราก็สามารถแก้ปัญหานี้ได้โดย กำหนดตัวแปรที่ตำแหน่ง BP - 1 ให้มันเกินไว้ตัวนึง จะได้เป็น

 Double:
  REF a -2
 PUSH 0
 REF rv 1
 VAR 1
 REF x 2
 PVAR x
 PVAR a
 LOAD
 STORE
 PVAR rv
 PVAR a
 LOAD
 PVAR x
 LOAD
 ADD
 STORE
FVAR
  RETURN

แต่ ... แบบนี้มันยุ่งยากจัง ... เรากำหนดคำสั่งใหม่มันจะง่ายกว่านะ ... ก็สมมติซะว่าคำสั่ง RETURN มันจะรวม FVAR ไปด้วยเลย แบบนี้

RETURN
  1. POP ค่า Return Code ออกมาเก็บไว้ก่อน
  2. ถ้า SP ≠ BP ก็ POP ค่าอื่น ๆ ทิ้งไปเรื่อย ๆ จนกว่า SP = BP
  3. POP ค่ามาใส่ไว้ใน BP
  4. POP อีกค่ามาใส่ไว้ใน PC
  5. PUSH ค่า Return Code ที่เก็บไว้ คืนลงไปใน Stack
ข้อดีของการทำแบบนี้ ไม่ใช่แค่เราลดคำสั่ง FVAR ได้แล้ว แต่เรายังประหยัดที่สำหรับ return value ไป 1 ที่ พร้อมกับป้องกันการ POP ไม่หมดได้ด้วย ... code ใหม่ของเราจะเหลือแค่นี้

 Double:
  REF a -2
 VAR 1
 REF x 1
 PVAR x
 PVAR a
 LOAD
 STORE
 PVAR a
 LOAD
 PVAR x
 LOAD
 ADD
  RETURN

Friday, November 18, 2005

มาลองทำ Assembler กัน (Literal)

Literal

ลองดู code ภาษา C ข้างล่างนี้

 int main()
 {
  char *msg = "ABC";
  printf("%s\n", msg);
  return 0;
 }

เราจะแปลงมันเป็นภาษา assembly ได้แบบนี้

 main:
  VAR 1
  REF msg 1
 PVAR msg
 PUSH literal0
 STORE
 PUSH literal1
 PVAR msg
 LOAD
 PUSH printf
 CALL
 FVAR
 PUSH 0
 RETURN
 literal0: "ABC"
 literal1: "%s\n"
 printf:
 ...

สมมติว่า string "ABC" และ "%s\n" ใช้เนื้อที่ตัวละ 1 word เราจะได้ object code สุดท้ายแบบนี้

 0000h: PUSH 0
 0002h: PBASE
 0004h: PUSH 1
 0006h: SUB
 0008h: PUSH 0024h
 000Ah: STORE
 000Ch: PUSH 0025h
 000Eh: PBASE
 0010h: PUSH 1
 0012h: SUB
 0014h: LOAD
 0016h: PUSH 0026h
 0018h: CALL
 001Ah: PUSH 0
 001Ch: MUL
 001Eh: ADD
 0020h: PUSH 0
 0022h: RETURN
 0024h: "ABC"
 0025h: "%s\n"
 0026h: ...

Thursday, November 17, 2005

มาลองทำ Assembler กัน (พื้นฐาน)

จริง ๆ แล้ว ภาษา assembly มันก็ภาษาเครื่องแหละ แต่มันเขียนสะดวกกว่านิดนึง ... อะไรที่เราควรจะกำหนดเพิ่มไว้ก่อนหละ? ก็เรื่อง label กับ ตัวแปรไง

Local Variables (อีกแล้ว)

สมมติว่า เราจะเขียนว่า

  void f()
  {
    int x;
    int y;
    x = 0;
    y = x + 500;
  }

เดิมเราจะเขียนว่า

  f:
    VAR 2
    PBASE
    PUSH 1
    SUB
    PUSH 0
    STORE
    PBASE
    PUSH 2
    SUB
    PBASE
    PUSH 1
    SUB
    LOAD
    PUSH 500
    ADD
    STORE
    ...
    FVAR
    PUSH ค่ามั่ว ๆ อะไรก็ได้
    RETURN

จะเห็นว่า การอ้างถึงตัว y จะต้องใช้ 3 คำสั่ง คือ

    PBASE
    PUSH 2
    SUB

เพื่อลดเรื่องยุ่งพวกนี้ เราก็กำหนดภาษาใหม่ แบบนี้

  f:
    VAR 2
    REF x 1 (บอกให้ x = BP - 1)
  REF y 2 (บอกให้ y = BP - 2)
    PVAR x
    PUSH 0
    STORE
    PVAR y
    PVAR x
    LOAD
    PUSH 500
    ADD
    STORE
    ...
    FVAR
    PUSH ค่ามั่ว ๆ อะไรก็ได้
    RETURN

Labels

เราใช้ Label ไปหลายทีแล้วโดยที่ไม่ได้พูดถึง ... จริง ๆ แล้ว การจะกระโดดไปที่ label ต่าง ๆ จำเป็นจะต้องรู้ address ของ label เหล่านั้น ...

ดังนั้น Assembler ของเรา จะต้องมีความสามารถในการ แปลง label เหล่านั้น ให้เป็น address จริง ๆ

สมมติว่ามี code แบบนี้

  int f()
  {
    int x;
    int y;
    do {
    x = ReadFromSomewhere();
      y = ReadFromSomewhere();
    } while (x != y);
    return 0;
  }

จะเขียนเป็น Assembly ได้แบบนี้

  f:
    VAR 2
    REF x 1
    REF y 2
  loop:
    PVAR x
    PUSH ReadFromSomewhere
    CALL
    PVAR y
    PUSH ReadFromSomewhere
    CALL
    PVAR x
    LOAD
    PVAR y
    LOAD
    SUB
    PUSH loop
    JNZ
    FVAR
    PUSH 0
    RETURN

ซึ่ง ตอนที่แปลเป็นภาษาเครื่อง เราจะต้องรู้ 3 อย่างคือ
  • ตำแหน่งเริ่มต้นของ f → สมมติว่าเป็น 1234h
  • ตำแหน่งเริ่มต้นของ ReadFromSomewhere → สมมติว่าเป็น 5678h
  • ขนาดของ instruction → สมมติว่าเป็น 2
จากตำแหน่งเริ่มต้นของ f และขนาดของ instruction เราจะสามารถหาตำแหน่งของ loop ได้ ทำให้สามารถแปล assembly ข้างบนเป็นภาษาเครื่องได้ ดังนี้

  1234h: PUSH
  1236h: PUSH
  1238h: PBASE
  123Ah: PUSH 1
  123Ch: SUB
  123Eh: PUSH 5678h
  1240h: CALL
  1242h: PBASE
  1244h: PUSH 2
  1246h: SUB
  1248h: PUSH 5678h
  124Ah: CALL
  124Ch: PBASE
  124Eh: PUSH 1
  1250h: SUB
  1252h: LOAD
  1254h: PBASE
  1256h: PUSH 2
  1258h: SUB
  125Ah: LOAD
  125Ch: SUB
  125Eh: PUSH 1238h
  1260h: JNZ
  1262h: PUSH 0
  1264h: RETURN

คราวหน้า มาดูเรื่อง Literal กันนะ

Wednesday, November 16, 2005

มาลองออกแบบ Abstract Instruction Set กัน (ตอนต่อ)

ต่อจาก มาลองออกแบบ Abstract Instruction Set กัน (ตอนแรก) เลยนะ

ครั้งนี้ จะพูดถึงการคำสั่งอย่างย่อ ... เรียกว่า เป็น Higher-Level Assembly ละกัน ... เราจะพัฒนาคำสั่งไปเรื่อย ๆ แบบนี้ จนมันเป็นภาษาชั้นสูงไปเลย

Local Variables

เราสามารถจองตัวแปรบน stack ได้ด้วยคำสั่ง PUSH เช่น สมมติว่าเรามี code ภาษา C แบบนี้

void f()
{
int x;
int y;
x = 0;
y = x + 500;
...
}

เมื่อเราเรียกคำสั่ง f เราจะจองเนื้อที่บน stack ให้กับตัวแปร x และ y ได้ด้วยคำสั่ง PUSH แล้วเมื่อเราจะใช้ตัวแปรพวกนี้ เราก็อ้างถึงจากตำแหน่ง BP (x คือ BP และ y คือ BP - 1) ...

f:
PUSH ค่าเริ่มต้นของ x
PUSH ค่าเริ่มต้นของ y
PBASE
PUSH 0
STORE
PBASE
PUSH 1
ADD
PBASE
LOAD
PUSH 500
ADD
STORE
...
POP
POP
PUSH ค่าอะไรก็ได้สำหรับ return
RETURN

แต่เอ๊ะ ... คราวที่แล้วบอกว่า ไม่มีคำสั่ง "POP" หนิ ... แล้วเราจะทำให้มัน POP ได้ไงหละ? ... มันก็ต้องอ้อม ๆ หน่อยแหละ ใช้ความรู้ที่ว่า อะไรคูณ 0 ก็ได้ 0 แล้วก็ อะไรบวก 0 ก็ได้ตัวเดิม เราจะสร้างคำสั่ง POP ได้จาก

PUSH 0
MUL
ADD

แล้วถ้ามี POP หลาย ๆ ตัวติดกัน เราก็แค่เพิ่ม MUL ตรงกลางเข้าไป เช่น

จาก
POP
POP
POP

กลายเป็น
PUSH 0
MUL
MUL
MUL
ADD

Abbreviated Form

เพื่อให้เขียนง่าย แทนที่เราจะเขียน PUSH ซ้ำ ๆ สำหรับตัวแปรหลาย ๆ ตัว เราจะเขียนว่า

VAR n

เพื่อหมายถึงการ PUSH เปล่า ๆ ไป n ครั้ง เป็นเนื้อที่ของตัวแปร n ตัว ส่วนการ POP เราก็จะเขียนว่า

FVAR

(ย่อมาจาก Free VAR) เพื่อหมายถึง PUSH 0, MUL, MUL, MUL, ..., ADD ที่มีจำนวน MUL เท่ากับ n ของคำสั่ง ALLOC ก่อนหน้านี้

Dynamic Allocation

เนื่องจาก ... การจองเนื้อที่สำหรับตัวแปรบน heap เป็นสิ่งที่ทำกันบ่อยมาก ๆ เราก็เลย สมมติว่ามีคำสั่งสำหรับทำงานนี้เลยละกัน

ALLOC

การทำงานคือ
  • POP ค่าบนสุดของ Stack ออกมา ให้เป็นขนาด memory block ที่ต้องการ
  • ไปค้นหาเนื้อที่ว่างจาก heap
  • PUSH ค่า address คืนลงไปใน Stack
เพื่อให้การคืน memory ทำได้ง่ายขึ้น เราจะจองเนื้อที่ให้เกินที่ขอไปนิดนึง เพื่อใส่ขนาดของ block ไว้ข้างหน้า address ที่คืนออกมา ผลก็คือ คำสั่ง

FREE

จะต้องการ POP ค่าจาก stack เพียงค่าเดียว คือ address

ตัวอย่างเช่น

void f()
{
int* x;
x = new int;
...
}

f:
VAR 1 (สมมติว่าขนาดของ pointer = 1)
PBASE
PUSH 1 (สมมติว่าขนาดของ int = 1)
ALLOC
STORE
...
FVAR
PUSH ค่าอะไรก็ได้สำหรับ return
RETURN

สรุปคำสั่งตอนนี้

จริง ๆ คำสั่ง ALLOC กับ FREE มันไม่ใช่คำสั่งพื้นฐานที่ CPU ควรจะมีหรอกนะ มันเป็น OS-level Instruction หนะ วิธีสร้าง ALLOC กับ FREE จริง ๆ ไว้จะบอกทีหลัง แต่ตอนนี้สมมติว่ามีให้ใช้เลยละกัน

Minimal Instruction Set + ALLOC & FREE
PUSH
PBASE
LOAD
STORE
JPOS
CALL
RETURN
NAND
NEG
ADD
MUL
ALLOC
FREE

Abbreviations
JMP
JNEG
JZ
JNZ
NOT
AND
OR
XOR
IFF
SUB
DIV
MOD
VAR
FVAR
...

แล้วจะมาเพิ่ม abbreviation อีกเรื่อย ๆ นะ

Tuesday, November 15, 2005

มาลองออกแบบ Abstract Instruction Set กัน (ตอนแรก)

ขอโทษล่วงหน้า ถ้าทำให้ใครบางคนอ่านเรื่องนี้ไม่รู้เรื่องตั้งแต่ต้น ...

บังเอิญว่า อยากจะเอาเรื่องเกี่ยวกับการออกแบบ Instruction Set ของ CPU มาให้ดู ๆ กันบ้างหนะ

Abstract Instruction Set

จุดประสงค์การออกแบบชุดคำสั่ง (Instruction Set) นี้ ไม่ใช่เพื่อให้มันประสิทธิภาพสูงสุด หรือว่าทำเป็นวงจรง่ายหรอกนะ แต่ อยากจะทำให้มันทำงานได้ครบ โดยที่มีคำสั่งน้อย ๆ มากกว่า

Chosen Design: Stack Machine

Stack Machine เป็นแนวคิดที่ว่า Operation ทั้งหลาย ทำบน Stack ... คิดว่าแบบนี้น่าจะทำให้ลดจำนวนคำสั่งลงได้เยอะ

ข้อเสียก็คือ การจะทำอะไรอย่างนึง มันต้องมีหลายคำสั่งน่ะสิ แล้วก็ การทำ Pipelining จะยากด้วย แต่ขอไม่สนเรื่องนี้ก่อน

เหตุผลสนับสนุนอีกอย่างนึงที่ทำให้เลือก Operation on Stack ก็คือ เวลาทำ compiler ให้แปล source code เป็น machine code เนี่ย มันจะค่อนข้างง่ายและตรงมาก (แต่ประสิทธิภาพก็ไม่ได้ดีเท่าไหร่แหละ)

First Two Opcodes: PUSH and POP

เวลาจะทำ Stack ใคร ๆ ก็ต้องคิดถึง Push กับ Pop แน่ ๆ เราก็กำหนดเลยละกันว่า เราจะมีสองคำสั่งนี้

ผลก็คือ เราสามารถสร้างให้คำสั่งอื่น ๆ ไม่รับ operand เองโดยตรงได้ เช่น

คำสั่ง A = B + C

Instruction Set ทั่วไป
ADD A, B, C

Stack-based Operation ของเรา
PUSH B
PUSH C
ADD
POP A

ว่าแต่ว่า ... เราจะระบุสิ่งที่จะ PUSH กับ POP ได้ยังไงหละ?

Types of Operands

เนื่องจากเราจะลดความซับซ้อนให้เหลือน้อยที่สุด เราจะยอมให้มี operand ได้แค่แบบเดียวแบบ คือ
  • Immediate
ไว้จะมาอธิบาย ว่า addressing แบบอื่น สามารถทำได้จากสองแบบนี้ แต่เราต้องพึ่งคำสั่งอื่น ๆ เช่น LOAD กับ ADD

Required Registers

เราจะให้มี register เพียง 3 ตัว ที่สามารถยุ่งเกี่ยวได้ด้วย machine instruction คือ
  • Program Counter (PC) = Address ของคำสั่งปัจจุบัน
  • Base Pointer (BP) = Address แรกของ Local Variable ปัจจุบัน
  • Stack Pointer (SP) = Address ของ Top-of-stack
โดยทั้งสามตัวนี้ ควรจะใช้ Address Space เดียวกัน (Virtual ก็ได้)

สมมติว่า SP จะลดค่าเมื่อ PUSH และเพิ่มค่าเมื่อ POP นะ (ทำตามแบบที่เค้านิยมกัน)

Indirect Indexing: PBASE

เนื่องจาก Base Pointer (BP) เป็น register ที่ควรจะสามารถนำค่าไปบวก-ลบได้ ดังนั้น เราจึงควรจะสร้างคำสั่งที่ใช้อ่านค่า BP ดังนี้

PBASE = Push ค่าของ BP ขึ้น Stack

LOAD and STORE

เราจะกำหนดให้ คำสั่ง LOAD จะใช้ operand เป็นตัวบนสุดของ stack ตัวเดียว มีการทำงานคือ
  1. เอาค่าบนสุดของ stack ไปเป็น address อ้างอิง memory
  2. อ่านค่าจาก memory ในตำแหน่งนั้น
  3. เอาค่าที่อ่านได้ มาแทนที่ในตำแหน่งบนสุดของ stack (ที่เคยเป็น address)
ส่วนคำสั่ง STORE จะใช้ operand 2 ตัว มีการทำงานคือ
  1. POP ตัวแรกออกจาก stack ใช้เป็น address อ้างอิง memory
  2. POP ตัวที่สองออกจาก stack ใช้เป็นค่าที่จะเขียนลง memory
  3. เขียนค่าที่ได้ (จากการ POP ครั้งที่สอง) ลงใน memory (address ได้จากการ POP ครั้งแรก)
จะว่าไป ... LOAD มันก็คือ PUSH แล้ว STORE มันก็คือ POP น่ะแหละ

สังเกตดี ๆ หละ ว่า จริง ๆ เราไม่ต้องมีคำสั่ง POP นะ!!!

Logical Functions: NOT, AND, OR, XOR, IFF

ถึงแม้ว่า จริง ๆ แล้วเราสามารถใช้แค่ NAND หรือ NOR เพียงอย่างเดียวได้ แต่ตรงนี้ ไม่ขอประหยัดจำนวน Opcode นะ เพราะว่ามันไม่ได้เป็นสาระสำคัญเท่าไหร่ (ถ้าอยากจะสร้างแบบประหยัด ให้มันมีแต่ NAND หรือมีแต่ NOR เวลาทำ compiler ก็จะเหนื่อยหน่อย เท่านั้นเอง)

Arithmetic Functions: NEG, ADD, SUB, MUL, DIV, MOD, EXP, LOG, ...

พวกนี้ก็เหมือนกัน ... จริง ๆ มีแค่ NEG ADD แล้วก็ MUL ก็น่าจะพอแล้ว แต่การประหยัดจำนวนคำสั่งตรงนี้ ก็ไม่ใช่สาระสำคัญเหมือนกัน ดังนั้นเราจะถือว่า คำสั่งพวกนี้ มีหมดเลย ก็แล้วกัน

Classical Modes of Addressing

เนื่องจาก Operand เรา มีแต่แบบ Immediate การอ้างถึง Operand ในลักษณะอื่น ๆ แบบที่เครื่องทั่ว ๆ ไปเค้าทำได้ มันจะต้องใช้หลายคำสั่งหน่อยนะ เช่น

Target: Value at memory address X
Abbreviation: [X]
How to PUSH that?
PUSH X
LOAD

Target: Value at memory address BP + X
Abbreviation: [BP + X]
How to PUSH that?
PBASE
PUSH X
ADD
LOAD

Target: Value at memory address (BP + value at X)
Abbreviation: [BP + [X]]
How to PUSH that?
PBASE
PUSH X
LOAD
ADD
LOAD

Target (in C): Array[Index]
Abbreviation: [BP + array + [BP + index]]
How to PUSH that?
PBASE
PUSH array
ADD
PBASE
PUSH index
ADD
LOAD
ADD
LOAD

Simple Branch Instructions: JMP, JPOS, JNEG, JZ, JNZ
  • JMP: POP → PC
  • JPOS: POP → เก็บไว้ แล้ว POP อีกที ถ้าได้ค่าเป็นเลขบวก (มากกว่า 0) ถึงจะกระโดดไปยัง address ที่เก็บไว้
  • JNEG: คล้าย ๆ กับ JPOS แต่จะกระโดดถ้าค่าที่ POP ออกมาครั้งที่ 2 เป็นเลขติดลบ
  • JZ: POP → เก็บไว้ แล้วก็ POP อีกที ถ้าได้ค่าเป็น 0 ถึงจะโดดไปยัง address ที่เก็บไว้
  • JNZ: คล้าย ๆ กับ JZ แต่เงื่อนไขการกระโดดตรงกันข้าม
จริง ๆ จะมีแต่ JPOS ก็ได้แหละ ที่ไม่ตัดตัวอื่นออก ก็เพราะว่ามันไม่ใช่สาระสำคัญ (อีกแล้ว)

Subroutine: CALL, RETURN

คำสั่ง CALL จะวุ่น ๆ หน่อย เพราะมีการทำงานหลายขั้น คือ
  1. POP ค่า address ที่จะกระโดดไป เก็บไว้
  2. PUSH ค่า PC + 1 ไว้
  3. PUSH ค่า BP ไว้
  4. กำหนดค่าให้ BP = SP
  5. กำหนดค่าให้ PC = address ที่ POP ไว้ตอนแรก (ซึ่งก็คือ การกระโดดนั่นเอง)
ส่วนคำสั่ง RETURN จะทำงานกลับกันกับ CALL คือ
  1. POP ค่า Return Code ออกมาเก็บไว้ก่อน
  2. POP ค่ามาใส่ไว้ใน BP
  3. POP อีกค่ามาใส่ไว้ใน PC (ซึ่งก็คือ การกระโดดกลับ)
  4. PUSH ค่า Return Code คืนลงไปใน Stack
จริง ๆ แล้ว ตอนที่ RETURN จะไม่เผื่อที่สำหรับ Return Code ก็ได้ แต่อันนี้เผื่อไว้เพื่อความสะดวกหนะ

Local Variable and Parameters

ถ้าต้องการส่งผ่าน parameter ให้กับ function เราก็จะใช้วิธี PUSH ใส่ stack ไว้ก่อน เช่น
  1. PUSH A
  2. PUSH B
  3. PUSH CustomAdd
  4. CALL
  • ถ้า BP หลัง CALL = x
  • SP ก่อน CALL จะ = x + 1
  • ตำแหน่งของ B ก็เลย = x + 2
  • และ ตำแหน่งของ A ก็ = x + 3
สรุปก็คือ parameter ตัวที่ PUSH มาหลังสุด (ไม่นับ address ของฟังก์ชัน ซึ่งในตัวอย่างนี้คือ CustomAdd) จะมี address เป็น BP + 2

CustomAdd:
  1. PBASE
  2. PUSH 2
  3. SUB
  4. LOAD
  5. PBASE
  6. PUSH 3
  7. SUB
  8. LOAD
  9. ADD
  10. RETURN
สรุปคำสั่ง

ชุดคำสั่งเล็กสุด
PUSH
PBASE
LOAD
STORE
JPOS
CALL
RETURN
NAND
NEG
ADD
MUL

คำสั่งลดความเหนื่อย
JMP
JNEG
JZ
JNZ
NOT
AND
OR
XOR
IFF
SUB
DIV
MOD
...

ตอนนี้เราก็ได้ Instruction Set คร่าว ๆ แล้ว แต่เราไม่พูดถึงขนาดของข้อมูลในแต่ละช่องของ Stack เลยนะเนี่ย ... ก็เลยเรียกว่า Abstract Instruction Set ไงหละ

Monday, November 14, 2005

การบวกลบเลขจำนวนเต็มไม่ติดลบ

เนื่องจาก การคิดเลขในฐานอะไรก็เหมือนกันหมด แต่เราอยากทำในกรณีที่มันเป็นฐาน 2 เพราะว่า คอมพิวเตอร์มันเป็นฐานสอง ... มาดูกันว่า การบวกเลขฐานสอง ทำกันยังไงนะ



จริง ๆ แล้ว ก็เหมือนกับฐาน 10 น่ะแหละ แต่มันง่ายกว่าด้วยซ้ำ เพราะว่า ผลลัพธ์มีแค่ 0 กับ 1 ดังนั้น ความเป็นไปได้ทั้งหมดของการบวกกันในแต่ละหลัก คือ ... (ตัวทด ใช้สีแดงนะ)

กรณีที่ไม่มีตัวทด (ตัวทด = 0)
0 + 0 = 00
0 + 1 = 01
1 + 0 = 01
1 + 1 = 10

กรณีที่มีตัวทด (ตัวทด = 1)
1 + 0 + 0 = 01
1 + 0 + 1 = 10
1 + 1 + 0 = 10
1 + 1 + 1 = 11

พอได้การบวกทุกแบบแล้ว เราก็ลองเอามาใช้ดู















ตอนนี้ก็บวกเป็นละ ... แล้วการลบหละ?

Sunday, November 13, 2005

เลขจำนวนเต็มไม่ติดลบ

ที่ผ่าน ๆ มา เราก็รู้กันไปเรียบร้อยแล้วเรื่อง การแปลงฐานเลข คราวนี้ก็ ขอตั้งข้อกำหนดเบื้องต้นไว้นิดนึงนะ คือ

ข้อมูลในคอมพิวเตอร์ จะอยู่ในรูปลำดับของเลขฐานสอง ที่มีความยาวจำกัด
ความยาวของลำดับ = จำนวน bit ของข้อมูล

แล้วก็ ขอกำหนดคำที่จะใช้เพื่อให้คุยกันง่ายขึ้น คือ

ข้อมูล n bit = เลขฐานสอง n หลัก

จำนวนเต็มไม่ติดลบ ที่สามารถแทนได้ด้วย n bit

คิดด้วยหลักการง่าย ๆ ว่า ข้อมูล 1 bit สามารถเป็นได้ 2 แบบ คือ 0 กับ 1 ดังนั้น

ข้อมูล n bit สามารถเป็นได้ 2n แบบที่แตกต่างกัน

เนื่องจาก จำนวนเต็มที่ไม่ติดลบ 2n ตัวแรก ก็คือ

0, 1, 2, ..., 2n - 1

ดังนั้น ข้อมูล n bit จะสามารถแทนจำนวนเต็มไม่ติดลบที่มีค่าน้อยกว่า 2n ได้ 1 ตัว

Byte

1 byte = 8 bits

ดังนั้น ข้อมูล 1 byte จะแทนจำนวนเต็มไม่ติดลบที่มีค่าน้อยกว่า 28 ได้ 1 ตัว

หมายเหตุ: แทนที่จะมองว่า 1 byte = เลขฐานสอง 8 หลัก เราอาจจะมองว่า 1 byte = เลขโดดฐาน 256 ก็ได้

เลขฐาน 16

ในโปรแกรมคอมพิวเตอร์พวกที่ให้เห็นค่าใน memory เรามักจะเห็นเลขฐาน 16 กันบ่อยพอควร แล้วมันก็จะอยู่เป็นคู่ ๆ ด้วย สาเหตุที่เค้านิยมเขียนเลขฐาน 16 อยู่เป็นคู่ ๆ ก็เพราะว่า มันสั้นกว่าการเขียนเป็นเลขฐานสอง แล้วที่มันใช้ได้ก็เพราะว่า

24 = 16 → เลขฐาน 16 ยาว 1 หลัก = ข้อมูล 4 bit
16 × 16 = 256 → เลขฐาน 16 ยาว 2 หลัก = ข้อมูล 1 byte

ดังนั้น

เลขฐาน 16 ยาว 2 หลัก = 1 byte

ตัวอย่าง

10102 = A16 = 10
11012 = D16 = 13
1010 11012 = AD16 = 173

ความนิยมอีกเรื่อง

เนื่องจาก การจะเขียนฐานเลขห้อย ๆ เนี่ย บางทีมันทำยาก (เช่น ในคอมพิวเตอร์สมัยก่อน หรือในหน้าจอของเครื่องอะไรก็ตามที่เป็น Text Mode) เค้าเลยนิยมเอา h ห้อยท้ายแทน (h มาจาก hexadecimal ← hexa + dec = 6 + 10) ส่วนเลขฐานสอง บางที่ก็เอา b ห้อยท้ายแทนการห้อยสอง เช่น

ADh = 173
11011010b = DAh = 218

จริง ๆ เครื่องหมายอื่น ๆ ก็มีอีก ไว้จะค่อย ๆ เอามาให้ดูบ้างละกันนะ