كما هو واضح من توقيعي أنا هذه الأيام أسلي نفسي بحل مسائل Project Euler، وهو أمر أنصح به الجميع لأنها طريقة رائعة (ومسلية) لتمرين مهارات حل المسائل وتعلم بعض المبادئ المتقدمة في البرمجة كما سنرى بعد قليل. قبل قليل كنت أحل المسألة رقم 44. اختصاراً لدينا متسلسلة حسابية بها عناصر لها معادلة رياضية معينة تدعي pentagonal. السؤال كان إيجاد رقمين ضمن هذه المتسلسلة يكون مجموعهما والفرق بينهما كلاهما أيضاً pentagonal. ومشي معي الحال. في المرة الأولى التي شغلت فيها البرنامج كتبت شرط إيجاد الحل داخل الـloop بهذا الشكل:
if (newP-oldP) in pentagonals and isP(newP+oldP):
الشطر الذي على اليسار يبحث عن فرق الرقمين داخل List بها الأعداد الـpentagonal التي تم حسابها مسبقاً. والشطر الذي على اليمين يقوم بنداء الدالة isP التي تقوم حسابياً بتحليل المجموع لمعرفة إذا كان يستوفي شروط متسلسلة pentagonal مقدماً. يجب طبعاً للحل استيفاء الشطرين. وبالفعل وجد البرنامج الحل في حوالي 101 ثانية. وهو رقم لا بأس به. ولكنني وضعت هدفاً لنفسي في جميع مسائل Euler أن يتم الحل في أقل من دقيقة. عندها تذكرت أن عملية البحث داخل List هي عملية مكلفة جداً إذا قارناها بالعمليات الحسابية الموجود داخل isP. وبما أنني وضعت عملية البحث في الشطر الأيسر فهذا يعني أن عملية البحث ستتم في كل iteration. وهذا مكلف فعلاً! ولكن لحسن الحظ فالجمل الشرطية في بايثون تدعم الـshort circuit. أي أنه في حال عدم استيفاء الشطر الأول من جملة الشرط فالمفسر لن ينفذ بقية الجملة. أي أنه إذا وضعت عملية isP الخفيفة أولاً فهذا يضمن أن عملية البحث الثقيلة لن تتم إلا إذا نجحت isP. وأصبح الكود:
if isP(newP+oldP) and (newP-oldP) in pentagonals:
النتيجة؟ البرنامج وجد الحل في 6.5 ثانية! أي تحسن 1580% في الأداء بمجرد قلب الشطرين. وهذا رقم كبير جداً! أعتقد أن هذا دليل جيد على أهمية معرفة كيف تعمل اللغة التي تستخدمها وراء الكواليس.
* ملاحظة: للفائدة وضعت البرنامج كاملاً كمرفق. ولو أنني أنصح الكل أن يحاول حل المسألة بنفسه قبل الاطلاع على الكود.



