Category Archives: programming

วิทย์ม.ต้น: รู้จัก Recursion,ใช้ Scratch คำนวณห.ร.ม., ตัวเลขเป็นจำนวนเฉพาะหรือไม่

วันนี้เด็กๆม.ต้นได้เรียนรู้เรื่อง Scratch  เพิ่มเติม ให้รู้จักการแปลงขบวนการคิดไปเป็นโปรแกรมครับ

เด็กม.3 ทำความรู้จักการหาห.ร.ม. (GCD, Greatest Common Divisor) โดยใช้วิธีของยูคลิด (Euclid’s algorithm)  ที่อาศัยว่าถ้าจำนวนเต็มบวก a, b มีตัวหารร่วมมาก d  ผลต่าง  a-b  หรือ b-a ก็หารด้วย d ลงตัวเช่นกัน เราจึงสามารถเปลี่ยนปัญหาการหา ห.ร.ม. ของ a และ b เป็นปัญหาที่เล็กลงคือหา ห.ร.ม. ของ a และ a-b ถ้า a มากกว่า b หรือหา ห.ร.ม. ของ a และ b-a ถ้า b มากกว่า a

จาก https://en.wikipedia.org/wiki/Greatest_common_divisor#Using_Euclid's_algorithm
จาก https://en.wikipedia.org/wiki/Greatest_common_divisor#Using_Euclid’s_algorithm

การลบหลายๆครั้งตามวิธีด้านบนก็เหมือนกันหารแล้วดูว่าเหลือเศษเท่าไร เราจึงเขียนได้อีกแบบโดยอาศัยวิธี a mod b ที่หาเศษจากการหาร a/b

จาก https://en.wikipedia.org/wiki/Greatest_common_divisor#Using_Euclid's_algorithm
จาก https://en.wikipedia.org/wiki/Greatest_common_divisor#Using_Euclid’s_algorithm

ตัว a mod b นี้สามารถให้ Scratch คำนวณให้ได้ (เช่น 19/5 = 3 เศษ 4 ดังนั้น 19 mod 5 ก็คือ 4) ผมจึงให้เด็กๆคิดว่าจะบอกให้ Scratch คำนวณห.ร.ม. ให้เราอย่างไร

19 mod 5 = 4
19 mod 5 = 4

เด็กๆได้รู้จัก Custom Block ใน Scratch ซึ่งทำหน้าที่เหมือนฟังก์ชั่นในภาษาโปรแกรมอื่นๆ และได้เห็นว่า Custom Block เรียกตัวเองได้ ก็คือได้รู้จัก Recursive function นั่นเอง

หน้าตาการหาห.ร.ม.แบบเรียกตัวเอง (recursion) จะออกมามีหน้าตาประมาณนี้ครับ:

หาห.ร.ม.แบบเรียกตัวเอง (recursive function)
หาห.ร.ม.แบบเรียกตัวเอง (recursive function)

นอกจากเขียนการหาห.ร.ม.แบบเรียกตัวเองแล้ว เรายังสามารถเขียนแบบให้เป็น loop หรือการวนซ้ำๆจนพบคำตอบแบบนี้ด้วยครับ การวนซ้ำๆจะเรียกว่าแบบ iterative ครับ:

การหาห.ร.ม.แบบวนซ้ำๆ (iterative)
การหาห.ร.ม.แบบวนซ้ำๆ (iterative)

สำหรับเด็กม.1-2 ผมแนะนำว่า  Operators ต่างๆของ Scratch ทำอะไรบ้าง หน้าตา Operators ก็เช่นพวกนี้ครับ:

ตัวอย่าง Operator ใน Scratch
ตัวอย่าง Operator ใน Scratch

จากนั้นผมให้เด็กๆสอนให้  Scratch บอกว่าตัวเลขจำนวนเต็มบวกที่เราป้อนเข้าไปเป็นจำนวนเฉพาะหรือไม่ ให้เด็กๆสังเกตว่าถ้าได้ตัวเลขมาหนึ่งตัว เราก็ลองไล่หาตัวเลขที่น้อยกว่ามันไปลองหารดูว่าลงตัวหรือไม่ เด็กๆได้สังเกตว่าเราควรตรวจดูก่อนว่าเลขคือ  1 หรือ 2 หรือไม่ ถ้าเป็น 1 ก็ไม่เป็นจำนวนเฉพาะ ถ้าเป็น 2 ก็เป็นจำนวนเฉพาะ สำหรับเลข N ที่มากกว่า 2 เราก็เอา 2, 3, 4, …, ไม่เกิน N ไปลองหาร N ดูว่ามีตัวไหนหารลงตัวไหม ถ้ามีเราก็บอกได้ว่า N ไม่ใช่จำนวนเฉพาะ ถ้าไม่มีตัวไหนหารลงตัวเลยเราก็รู้ว่า N  เป็นจำนวนเฉพาะ  นอกจากนี้เด็กๆยังได้เห็นว่าจริงๆเราหาตัวหารที่ไม่มากกว่ารูทที่ 2 ของ N ก็พอ เพราะถ้ามีตัวหารที่มากกว่ารูทที่ 2 ของ N เราก็จะต้องเจอตัวหารอีกตัวที่น้อยกว่ารูทที่ 2 ของ N ไปก่อนแล้วแน่นอน

เด็กๆไปนั่งหัดเขียนกันประมาณ 1 ชั่วโมงครับ ก็ได้โปรแกรมกันทุกคน ใครทำได้ก่อนก็ไปให้คำปรึกษาคนที่ยังติดอยู่ ผมบอกว่าไม่ให้บอกกันแต่ให้ถามๆและชี้ๆส่วนที่อาจเป็นบั๊กจนทุกคนเข้าใจและทำได้เองกันหมด หลายๆคนตื่นเต้นมากที่คอมพิวเตอร์ตอบคำถามว่าเลขไหนเป็นจำนวนเฉพาะอย่างรวดเร็วเพราะวิธีที่เด็กๆทำด้วยมือมันทำได้ช้าและใช้กับเลขน้อยๆเท่านั้น เด็กๆได้ทดลองตรวจสอบเลขใหญ่ๆเช่น 15,485,863 และ 32,452,843  (เลขจำนวนเฉพาะตัวที่ล้านและสองล้านตามลำดับ) และพบว่ามันเป็นจำนวนเฉพาะ

หน้าตาโปรแกรมจะเป็นทำนองนี้ครับ:

 

ตัวเลขเป็นจำนวนเฉพาะไหม?
ตัวเลขเป็นจำนวนเฉพาะไหม?

วิทย์ม.ต้น: รู้จักช่อง The Royal Institution (RI) บน YouTube, เรียนรู้เขียนโปรแกรม Scratch ให้คำนวณเลขให้เรา

วันนี้เด็กๆมัธยมต้นได้รู้จักกับช่อง YouTube ที่มีประโยชน์และน่าดูมากครับ ช่องนี้คือช่อง The Royal Institution ซึ่งเผยแพร่ความรู้ต่างๆที่น่าสนใจ

ตัวอย่างคลิปน่าสนใจครับ คลิปแรกคือความรู้เรื่องจรวด:

เรื่องการระเบิด:

เรื่องการเผาเพชร  C + O2 -> CO2:

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

เด็กๆก็ไปนั่งคิดและค้นหาคำสั่งที่น่าจะใช้ได้

หลังจากปล่อยให้คิดและทำกันเองสักพัก ผมก็แสดงวิธีทำแบบหนึ่งให้เด็กๆดูเป็นไอเดีย

เริ่มโดยดูคำสั่ง ask ที่จะถามผู้ใช้ เมื่อผู้ใช้พิมพ์อะไรเข้าไป สิ่งที่พิมพ์เข้าไปจะไปอยู่ใน answer แล้วเราก็เอา answer ไปใช้ได้ ทำนองนี้ครับ:

เด็กๆรู้จักการใช้ join เพื่อเอาของต่างๆมาเรียงกันให้เป็นรูปแบบที่ต้องการ join (a, b) -> ab

join (a, join (b, c)) -> abc

join (a, join (b, join (c, d))) -> abcd

รู้จัก set ให้ตัวแปร (variable) มีค่าที่ต้องการ

หน้าตาโปรแกรมทั้งหมดก็จะเป็นประมาณนี้ครับ:

กดเข้าไปดูและเล่นได้ที่นี่นะครับ

พอเด็กๆเข้าใจกันดีแล้ว ผมก็บอกให้เด็กๆไปลองคิดทำเครื่องคิดเลขด้วย Scratch กันครับ

นอกจากนี้ผมก็ถามคำถามว่าถ้าเราฝากเงินไว้ 100 บาท ได้ผลตอบแทน 5%  (=5/100) ต่อปี ทิ้งไว้สิบปีเงินจะงอกเงยเป็นเท่าไรให้เด็กๆใช้ Scratch คิดครับ

คือวิธีทำก็ให้สังเกตว่าทุกปีที่ผ่านไป เงินเราจะงอกเงยเป็น (1+5/100) เท่าของเงินเมื่อต้นปี เราจึงสามารถคูณ 1.05 ทบไปเรื่อยๆทุกปี ถ้าเปลี่ยนเป็นภาษา Scratch ก็จะหน้าตาประมาณนี้ครับ

จะได้คำตอบว่าเมื่อผ่านไป 10 ปี เงิน 100 จะงอกเงยเป็นประมาณ  163 ครับ

ผมถามต่อว่าถ้าผลตอบแทนเป็น 20% (=20/100) แทนที่จะเป็น 5% ล่ะ เวลาผ่านไป 10 ปี เงิน 100 จะงอกเป็นเท่าไร

เราก็แค่เปลี่ยนโค้ดใน  Scratch นิดเดียว จาก 1.05 เป็น 1.20:

จะได้คำตอบว่าเมื่อผ่านไป 10 ปี เงิน 100 จะกลายเป็นประมาณ 620 ครับ โตเร็วกว่าที่เด็กๆเดาก่อนจะคำนวณไปมาก จะเห็นได้ว่าผลตอบแทนต่อปีที่ดูเหมือนต่างกันไม่เท่าไรทำให้ผลลัพธ์ต่างกันได้มากมาย เรื่องนี้เป็นเรื่องสำคัญเกี่ยวกับการเติบโตแบบ exponential ที่เราจะคุยกันต่อไปในอนาคตครับ

โจทย์แมลงวันบินระหว่างรถ (Two Trains Puzzle) และโปรแกรมที่เกี่ยวข้อง

(เขียนเพื่อรวบรวมโพสท์ต่างๆที่กระจายอยู่บน Facebook และจะได้เป็นที่โหลดโปรแกรมไปลองเล่นครับ โปรแกรมเป็นภาษา Mathematica นะครับ โปรแกรมอยู่ที่นี่ ถ้าไม่มี Mathematica สามารถลองใช้ได้ที่นี่ ถ้าไม่คุ้นเคยกับภาษานี้ลองเข้าไปดูที่ผมเขียนแนะนำที่นี่ครับ ถ้าอยากเขียนใหม่เป็น Python อาจต้องใช้โมดูล SymPy ช่วยนะครับ ถ้าจะดูโค้ดแต่ไม่มี Mathematica กดตรงนี้เพื่อดูไฟล์ PDF ครับ )

สัปดาห์ที่ผ่านมีมีดราม่าเรื่องข้อสอบ กพ. ที่ว่ามีรถสองคันอยู่ห่างกัน 40 กิโลเมตรวิ่งเข้าหากัน คันหนึ่งวิ่ง 60 กม/ชม อีกคันวิ่ง 40 กม/ชม มีแมลงวันที่บินกลับไปกลับมาระหว่างรถด้วยความเร็ว 80 กม/ชม คำถามคือแมลงวันบินได้ระยะทางเท่าไรก่อนที่รถจะชนกัน ถ้าเราไม่ซีเรียสเรื่องแมลงวันที่ไหนที่บินได้เร็วอย่างนั้น แถมยังเปลี่ยนความเร็วได้ทันทีเมื่อแตะรถอีก วิธีคิดง่ายๆก็คือระยะทางระหว่างรถทั้งสองลดลงด้วยอัตรา 60+40 = 100 กม/ชม ถ้าตอนเริ่มต้นรถห่างกัน 40 กิโล รถจะอยู่ติดกันที่เวลา 40/100 = 0.4 ชั่วโมง ดังนั้นแมลงวันก็จะบินอยู่ 0.4 ชั่วโมงคิดเป็นระยะทาง = 0.4 ชั่วโมง x 80 กิโลเมตร/ชม = 32 กิโลเมตร  (โจทย์นี้เป็นที่รู้จักกันในนาม Two Trains Puzzle เป็นเวลานานมากแล้ว มีตำนานว่ามีคนเอาปัญหานี้ไปถาม John von Neumann ผู้เป็นอัจฉริยะด้านคณิตศาสตร์และคอมพิวเตอร์ คุณ von Neumann ตอบทันที คนถามบอกว่าอ๋อคงรู้วิธีคิดลัดละสิ คุณ von Neumann บอกว่าวิธีลับอะไร ก็บวกอนุกรมอนันต์ธรรมดาไง)

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

คุณ Atis Yosprakob ทำ animation เรื่องนี้ไว้ที่ http://ayosp.info ด้วยนะครับ

ต่อมาอาจารย์ทีปานิส ชาชิโยถามว่าถ้าความเร็วของแมลงวันวิ่งไปทางซ้ายและขวาไม่เท่ากัน ระยะทางจะเป็นอย่างไร:

ผมดัดแปลงโปรแกรมแล้วลองบวกระยะทางส่งไปให้อาจารย์ดู แล้วอาจารย์ก็แสดงสูตรและวิธีทำดังนี้ครับ:

วิธีนี้เป็นวิธีบวกอนุกรมอนันต์ครับ วิธีแบบนี้เป็นวิธีที่ผมพยายามทำแต่ทำผิดเลยได้คำตอบผิดๆไม่ตรงกับโปรแกรมครับ

ช่วงเวลาประมาณเดียวกัน อาจารย์สุจินต์ วังสุยะก็แสดงวิธีทำอีกแบบหนึ่งที่ไม่ต้องบวกอนุกรมอนันต์ หน้าตาประมาณนี้ครับ:

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

หลังจากผมวาดกราฟไปสักพักผมก็สงสัยว่าจริงๆเราไม่ต้องใช้ความเร็วรถ A เลยนี่นา สิ่งที่สำคัญสำหรับการหาระยะทางมีแค่เวลาที่ใช้ทั้งหมด T และตำแหน่งที่รถชนกัน d กล่าวคือรถ A และ B จะวิ่งยังไงก็ได้ ตราบใดที่มันใช้เวลา T เพื่อมาชนกันที่ตำแหน่ง d, ระยะทางที่แมลงวันบินจะเท่ากับ:

S = ระยะทางที่แมลงวันบิน d = ตำแหน่งที่รถชนกัน T = เวลาที่รถชนกัน V1, V2 คืออัตราเร็วที่แมลงวันบินจากรถ A ไป B และจาก B ไป A
S = ระยะทางที่แมลงวันบิน d = ตำแหน่งที่รถชนกัน T = เวลาที่รถชนกัน V1, V2 คืออัตราเร็วที่แมลงวันบินจากรถ  A ไป  B และจากรถ  B ไป  A

ทั้งนี้รถทั้งสองคันต้องไม่เคยวิ่งแซงแมลงวันด้วยนะครับ (แปลว่าขนาด slope ของกราฟการเคลื่อนที่ของรถตอนแมลงวันไปถึงต้องไม่มากกว่าอัตราเร็วตอนแมลงวันบินหนีกลับมา)

วิธีแก้สมการก็ง่ายๆตรงไปตรงมาถ้าทำตามแบบอาจารย์สุจินต์ครับ ไม่ต้องบวกอนุกรมอนันต์ เป็นสมการเชิงเส้นสองตัวแปรสองสมการ:

T = เวลาที่รถชนกัน d = ตำแหน่งที่รถขนกัน t1 = เวลาทั้งหมดที่บินไปทางขวา t2 = เวลาทั้งหมดที่บินไปทางซ้าย
T = เวลาที่รถชนกัน
d = ตำแหน่งที่รถชนกัน
t1 = เวลาทั้งหมดที่บินไปทางขวา
t2 = เวลาทั้งหมดที่บินไปทางซ้าย

 

อันนี้เป็นสรุปในกระดาษทดหลังจากวาดกราฟดูไปเยอะๆครับ:

ตัวอย่างหน้าตากราฟการเคลื่อนที่แบบต่างๆที่แมลงวันบินระยะเท่ากันเพราะ T และ d เท่ากัน และรถไม่แซงแมลงวันครับ (T=0.4, d= 16):

หน้าตาโปรแกรมจะเป็นประมาณนี้ครับ โหลดได้ที่นี่นะครับ:

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