Oct 23, 2012

ถ้าฝนตกแล้วเก็บผ้า

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

ตัวอย่างเช่น "ถ้าฝนตก ผ้าที่ตากไว้จะเปียก" จะเห็นได้ว่า ฝนตกแล้วยังไงผ้าต้องเปียกแน่ๆ ไม่มีทางที่ฝนตกแต่ผ้าไม่เปียกได้เลย แต่เราจะไม่สามารถระบุได้เลยว่าหากฝนไม่ตกแล้วผ้าจะเปียกหรือไม่ (มันไม่เกี่ยวโยงกันเลย)

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

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

ทางแก้คือเปลี่ยนไปใช้รูปประโยค "ก ก็ต่อเมื่อ ข" แทน ซึ่งหมายความคือ "ถ้า ก แล้ว ข" และ "ถ้า ข แล้ว ก" ทั้งสองอย่าง

นั่นก็คือเปลี่ยนประโยคนั้นเป็น "ฝนตกก็ต่อเมื่อเก็บผ้า" หรือเพื่อให้อ่านได้เข้าใจง่ายขึ้น "เก็บผ้าก็ต่อเมื่อฝนตก" แบบนี้แล้ว การจะเก็บผ้าต้องทำตอนที่ฝนตกเท่านั้น ถ้าฝนไม่ตกห้ามเก็บผ้าเด็ดขาดครับ

Oct 17, 2012

โปรแกรมที่เขียนมันช้า...

เวลาเขียน Python แล้วต้อง implement อะไรประมาณนี้
numbers = [random() for r in range(1000)]

for i in range(100):
    print(max(numbers)**i)
จะระลึกตัวเสมอว่า implement ตรงๆ แบบนี้แล้วมันช้านะ แต่ถ้า input ไม่ได้ใหญ่จนน่าเป็นห่วง ก็ไม่มีเหตุผลที่จะเขียนให้ยากขึ้น เพราะการแก้โดยเอา max(numbers) ไปไว้เป็นค่าคงที่นอก loop แม้จะทำให้โปรแกรมเร็วขึ้นก็ตาม แต่ก็จะเสีย readability ไปบางส่วน เวลากลับมาอ่านอาจจะสับสนใน logic ว่าส่วนนี้มีไว้ทำอะไรกันแน่ แถมถ้าภายหลังโปรแกรมถูกพัฒนาจนซับซ้อนมากๆ แล้ว ค่า max(numbers) อาจไม่เท่ากันทุกรอบที่วน loop ก็ได้ ทำให้เกิดเป็น bug ซ่อนเร้นอีก

ส่วนถ้าต้องการประสิทธิภาพที่ดีกว่าเดิมมากๆ การแก้ Python จนอ่านยากอาจไม่ใช่ความคิดที่เข้าท่าเท่าไหร่ ลองถอดโปรแกรมเดิมมาเขียนบน C++ แบบเป๊ะๆ ก็คงได้ประมาณนี้
int main(void) {
    float numbers[1000];
    fill_with_random(numbers);

    for (int i=0; i<100; i++) {
        printf("%.32f\n", pow(max(numbers), i));
    }
    return 0;
}
(ตัวเลขขนาด array / loop ควรเปลี่ยนไปยังค่าสูงกว่านี้ เพื่อให้เห็นได้ชัดว่าโปรแกรมทำงานได้ช้าลง)

ถึงตอนนี้จะเห็นว่า max(numbers) มีผลอย่างมากต่อประสิทธิภาพโปรแกรม การย้ายมันออกมาไว้นอก loop จะเป็นการกระทำที่มีเหตุผลขึ้นทันที

แต่ถ้าโปรแกรมเรามีอะไรแบบนี้เป็นสิบเป็นร้อยที่หละ การย้ายมือเองไม่สนุกแน่

ทางออกก็ง่ายๆ บอกให้ gcc มันทำแทนเราไปซะ
$ gcc -O2 exp-max.cpp
เพียงเท่านี้ก็จะได้ code ที่ยังคง logic + readability เดิมเอาไว้อยู่ พร้อมทั้งโปรแกรมที่เร็วกว่าเดิมเยอะ

แต่ถ้าโปรแกรมใหญ่มากๆ ก็ต้องรอ compile กันนานหน่อยนะ :P



Oct 7, 2012

Nessun Dorma



คือปรกติเพลงประกอบโฆษณาที่เป็นเพลงคลาสสิก เคยเจอแต่พวกเพลงบรรเลงแฮะ ไม่ค่อยเจอ aria อะไรอย่างนี้ซักเท่าไหร่ จดเก็บไว้หน่อยๆ :3