Tag Archives: python

วิทย์ม.ต้น: Birthday Paradox ต่อ

วิทย์โปรแกรมมิ่งวันศุกร์นี้ เด็กๆม.3 เขียนโปรแกรมไล่ดูว่าต้องมีคนสักกี่คนอยู่ด้วยกันแล้วความน่าจะเป็นที่จะมีคนวันเกิดซ้ำกันบ้างเกิน 50% พบว่าต้องมีคน 23 คนครับ

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

เราวาดกราฟดูด้วย matplotlib ได้ดังนี้ครับ:

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

เช่นสมมุติว่ามีคนหลายคนใส่นาฬิกาโดยที่ไม่ได้ตั้งกันมาให้ตรงกับเวลามาตรฐานก่อน เข็มวินาทีของแต่ละคนก็อาจจะชี้เลขจาก 0 ถึง 59 ถ้าเราสมมุติว่าโอกาสที่เข็มชี้เลขต่างๆด้วยความน่าจะเป็นเท่าๆกัน เราก็สามารถหาโอกาสที่คน k คนจะมีเข็มวินาทีซ้ำกันอยู่ได้ด้วยฟังก์ชั่น prob_some_repeat(60, k) เราจะพบว่าเมื่อมีคน 10 คน ความน่าจะเป็นที่มีเข็มชี้ไปที่วินาทีซ้ำๆกันบ้างจะมากกว่า 50% ครับ

ด้วยคณิตศาสตร์ระดับสูงขึ้นไป เราจะสามารถคำนวณได้ว่าถ้ามีของให้เลือก N ชิ้น แล้วมีคน k คนมาเลือกสุ่มๆโดยโอกาสเลือกของแต่ละชิ้นเท่าๆกัน ความน่าจะเป็นที่จะมีการเลือกซ้ำจะมีค่า 50% เมื่อ k มีค่าประมาณ 1.2 √N เท่านั้นครับ

การบ้านคือให้เด็กๆไปทดลองหาว่าสำหรับของ 10, 10^2, 10^3, 10^4, 10^5, 10^6 ชิ้นต้องมีคนกี่คนเลือกถึงมีโอกาสเลือกซ้ำกันประมาณ 50% และใกล้กับค่า 1.2 √N ไหม

วิทย์ม.ต้น: Leap Year, Birthday Paradox, The Monty Hall Problem, ฝึก TrackeR

วิทย์โปรแกรมมิ่งวันศุกร์นี้ เด็กๆม.3 ดูเฉลยการบ้านเรื่องหาวันที่เป็น palindrome คืออ่านกลับหลังก็เหมือนอ่านปกติเช่นวันที่ 2020-02-02 ครับ ในการบ้านเด็กๆต้องไปหาวิธีหาว่าปีไหนมี 366 วัน (เป็น leap year) ด้วย กฎเกณฑ์คือดูปีเป็น ค.ศ. แล้วดูว่าถ้าปีหารด้วย 4 ลงตัวก็เป็น leap year แต่ถ้าหารด้วย 100 ลงตัวก็ไม่นับเป็น leap year แต่ถ้าหารด้วย 400 ลงตัวก็นับเป็น leap year

สาเหตุที่ต้องมีกฎเกณฑ์แบบนี้เพราะว่าโลกใช้เวลาประมาณ 365.242189 วัน (หรือ 365 วัน 5 ชั่วโมง 48 นาที 45 วินาที) คือในหนึ่งปีจะมีวันเกิน 365 วันไปเกือบๆ 1/4 วัน เราจึงต้องพยายามชดเชยประมาณเกือบๆทุกๆ 4 ปี

วิธีเขียนฟังก์ชั่นหา leap year ก็จะมีหน้าตาประมาณนี้ครับ:

ถ้าเขียนตามวิธีที่ Wikipedia แสดงไว้ก็จะมีหน้าตาแบบนี้:

เช็คดูว่าปีต่างๆมีจำนวนวันอย่างที่คาดหรือเปล่า ในสองพันปีมี leap year 485 ปีใช่ไหม และฟังก์ชั่น is_leap_year และ is_leap_year1 ทำงานเหมือนกันใช่ไหม:

ต่อจากนั้นผมก็แนะนำให้เด็กๆม. 3 รู้จักกับ Birthday Paradox ที่สมมุติว่าทุกปีมี 365 วัน และแต่ละวันมีคนเกิดเท่าๆกัน ดังนั้นถ้ามีคนเกิน 365 คนก็ต้องมีวันเกิดซ้ำกันแน่ๆ ถ้ามีคนเดียวก็ไม่มีวันเกิดซ้ำกันได้ ถ้ามีสองคนโอกาสที่วันเกิดจะซ้ำกันคือ 1/365 คำถามก็คือต้องมีคนสักกี่คนถึงจะมีโอกาสมีวันเกิดซ้ำกันประมาณ 50%

เด็กๆเดากันว่าอาจจะต้องมีสัก 100 คน เราจึงเขียนโปรแกรมคำนวณความน่าจะเป็นที่จะมีวันเกิดซ้ำกันถ้ามีคน k คนครับ

วิธีคำนวณง่ายที่สุดคือให้สังเกตว่าถ้าให้ p = ความน่าจะเป็นที่จะมีวันเกิดซ้ำกันในกลุ่มคน k คน และ q = ความน่าจะเป็นที่ไม่มีวันเกิดซ้ำกันเลยในกลุ่มคน k คนแล้ว จะได้ว่า p = 1 – q แล้วก็ไปคำนวณ q กันก่อน

สำหรับ k = 1 คน, q = 1 เพราะคน 1 คนไม่สามารถมีวันเกิดซ้ำกับใคร
สำหรับ k = 2 คน, q = 364/365 คือคนที่สองต้องเกิดไม่ซ้ำกับคนแรก
สำหรับ k = 3 คน, q = 364/365 x 363/365 คือคนที่สามก็ต้องไม่ซ้ำกับคนที่สองด้วย
ถ้าไล่ไปเรื่อยๆ สำหรับ k คน, q จะเท่ากับ (365-k+1)/365 คูณกับ q ของ k-1 คน

พอคำนวณ q เสร็จเราก็คำนวณ p จาก p = 1 – q

ให้เด็กๆม.3 ไปทำเป็นการบ้านคือเขียนโปรแกรมคำนวณ p, q และตอบคำถามว่าต้องมีคนสักกี่คนถึงจะมีโอกาสวันเกิดซ้ำกันบ้างประมาณ 50% ครับ

นอกจากนี้ผมยังให้เด็กๆม. 3 รู้จัก The Monty Hall problem (แปลเป็นภาษาไทยที่นี่) ด้วยครับ สถานการณ์เป็นแบบนี้:

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

จาก https://th.wikipedia.org/wiki/ปัญหามอนตี_ฮอลล์

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

ผมให้เด็กๆดูคลิปนี้ช่วงแรกก่อนเฉลย:

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

สำหรับเด็กม.1 ผมให้หัดใช้โปรแกรม Tracker เพื่อวัดระยะทาง ความเร็ว ความเร่งในวิดีโอคลิปต่างๆของเรากันครับ เป็นโปรแกรมฟรี open source และมีบน Windows, macOS, Linux

ผมเคยบันทึกตัวอย่างการใช้ไว้ที่นี่ครับ:

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

วิทย์ม.ต้น: ใช้ SymPy แก้สมการสัญญลักษณ์และตัวเลข, สั่งให้คอมพิวเตอร์ทำงานซ้ำๆแทนเรา

วิทย์โปรแกรมมิ่งวันศุกร์ครั้งนี้ เด็กม.3 ดูโจทย์นี้เพื่อแปลงเป็นสมการให้ SymPy แก้ปัญหาให้ครับ

เราแปลงเป็นสมการในตัวแปร x, y, z ให้ SymPy แก้ได้แบบนี้ครับ:

เราเอาค่า x, y, z ไปแทนค่าได้แบบนี้ คำตอบคือ 41:

ทดลองหาจุดตัดของวงกลมและเส้นตรงครับ:

ใช้คำสั่ง div หาผลหารและเศษการหารโพลีโนเมียลได้ด้วยครับ:

สำหรับเด็กม.1 เราพยายามหาค่า x ที่ทำให้ xx = 2 (จากตอนท้ายของวิดีโอข้างบน) เราทำโดยเดาก่อนว่า 11 = 1 และ 22 = 4 ดังนั้น x น่าจะอยู่ระหว่าง 1 กับ 2 แล้วเด็กๆก็ลองดูตรงกลางระหว่าง 1 กับ 2 ว่า 1.51.5 = 1.84… แสดงว่าคำตอบควรอยู่ระหว่าง 1.5 กับ 2 จึงลองดูตรงกลาง = 1.75 พบว่า 1.751.75 = 2.66 แสดงว่าคำตอบควรอยู่ระหว่าง 1.5 กับ 1.75 ถ้าเราทำต่อไปเราก็จะหาทางแบ่งครึ่งช่วงคำตอบไปเรื่อยๆ แต่เราหัดเขียนโปรแกรมให้คอมพิวเตอร์ไล่ให้เราได้ดังนี้ครับ:

พบว่า x = 1.5596104694623696…. จะทำให้ xx = 2 ครับ

ผมถามเด็กว่าถ้าจะหาค่า x ที่ทำให้ xx = 3 จะทำอย่างไร เด็กๆก็แก้โปรแกรมนิดนึงได้คำตอบ x = 1.8254550229248308… ทำให้ xx = 3 ครับ:

ผมถามเด็กม.1 ด้วยว่าถ้าคำนวณ (1+1/1)1, (1+1/2)2, (1+1/3)3, (1+1/4)4, …, (1+1/n)n โดยที่ n ใหญ่ขึ้นไปเรื่อยๆ ค่าที่คำนวณจะใหญ่ไปเรื่อยๆไหม เด็กๆก็ให้ไพธอนคำนวณให้ พบว่าผลการคำนวณจะประมาณ 2.71828… (ซึ่งเท่ากับค่าคงที่ออยเลอร์หรือค่า e นั่นเองครับ)