يونيو 29، 2009

ماهو الموقف من مونو Mono بكل حيادية و موضوعية؟

مند الإعلان عن التخلي عن برنامج Tomboy (الذي يعتمد على إطار العمل البرمجي مونو Mono) و تعويضه ببرنامج غنوت Gnote (الذي يعتمد على سي++) في الإصدار القادم من توزيعة فيدورا، و الأخبار تملأ الإنترنت بمخاوف البعض من مونو و المخاطر المستقبلية المتعلقة بالملكية الفكرية في حالة تم الإعتماد عليه لتطوير البرمجيات الحرة.

فما هو وضع مونو Mono من كل المخاوف و المخاطر التي تحوم حوله بكل موضوعية و حيادية؟


أولا، ما هو مونو؟
مونو عبارة عن إطار عمل برمجي حر و مفتوح المصدر صمم خصيصا ليكون بديل مفتوح المصدر للإطار البرمجي دوت نت (Net Framework) على منصة جنو/لينوكس، يونكس، ماك و حتى ويندوز.

و أين تكمن المخاوف؟
تقنية دوت نت هي من إبتكار و تطوير مايكروسوفت Microsoft و هذا يجعلها مالكة لتلك المنصة و بالتالي فهي تملك الأحقية في إمتلاك براءات الإختراع (patents). و فعليا في حوزتها العديد منها.

غير أن مايكروسوفت قامت في صيف 2001 بطلب إجتياز و إعتبار لغة سي شارب C# و اللغة العامة للبنية التحتية (Common Language Infrastructure) كمعيار قياسي موحد و معترف به من طرف ECMA و ISO. و للحصول على هذا الإعتراف يجب توفير التقنية بشروط معقولة وغير تمييزية، و فعلا هذا هو ما حصل. الشيء الذي يسمح للأخرين بإمكانية تطوير برمجيات تستخدم هذه المعايير دون تخوف.

لكن

الإطار البرمجي دوت نت يتكون من أجزاء أخرى لا ينطبق عليها هذا المعيار كـ:
  • WinForms: الذي يوفر الأدوات و المكونات المسؤولة عن توفير الواجهة الرسومية.
  • ADO.Net: الذي يوفر مكونات التواصل مع قواعد و خدمات الباينات.
  • ASP.Net: الذي يوفر مكونات تصميم المواقع الدينامكية و خدمات و برمجيات النت.
  • باﻹضافة إلى WPF, WCF, WF و LINQ
و بالتالي فإن هذه الأجزاء المهمة تبقى غير مغطات بأي ضمان أو رخصة تسمح بإستخدامها. و حتى مبادرة المصدر المشترك التي قامت بها مايكرسوفت في 2007 لا تقدم أي ضمان.


أين مونو من كل هذا؟
في البداية كان هذف مونو هو تطوير إطار عمل متوافق للمعيار القياسي الموحد لـدوت نت (ECMA/ISO). و قد تحقق هذا الهذف و هو مغطى بتصريح يسمح بإستخدامه من طرف اي شخص و لأي غاية.
اما اليوم فقد تمكن مونو من توفير دعم للأجزاء الثلاثة الاساسية الأخرى (WinForms و ADO.Net و ASP.Net) بالإضافة إلى مكونات  أخرى (برمجيات و مقاييس مفتوحة المصرد و موحدة) كـ  OpenGL و GTK و Mozilla.
و بما أن تلك الأجزاء الأخرى الخاضعة لمايكروسوفت لا يوجد عليها أي ضمان فإن إستخدامها لتطوير البرمجيات يحمل مجازفة يجب و ضعها في الحسبان.

لماذا تعتبر مجازفة؟
لأن مايكروسوفت كأية شركة اخرى تقوم بأبحاث و تنفق الأموال لتطوير التقنيات الجديدة/المبتكرة، و من الطبيعي أن تطالب بالحصول على براءات إختراع من مكتب الولايات المتحدة الامريكية لبراءات الإختراع و العلامات التجارية (USPTO) أو حتى من المكاتب المخصص لذلك في بلدان أجنبية.
و فور حصول أي شركة على براءة إختراع يصبح من حقها ترخيص تلك التقنية لأية جهة أخرى، كما يمكن أن تلاحق أية جهة طورت تقنية مطابقة لها. و مدة إمتلاكها هو 20 سنة!

لكن هل هذا دليل نوايا مايكروسوفت؟
أكدت مايكرسوفت في أكثر من مناسبة انها تريد إستخدام قانوني لملكيتها الفكرية و انها تفضل ترخيصها لصالح إعلاء قيمة و مردود الشركة بالنسبة لمالكي أسهم مايكروسوفت.
كما دخلت في نزاعات قضائية في أكثر من مناسبة و كانت آخرها مع شركة طوم طوم حول إنتهاك الملكية الفكرية بخصوص طريقة حفظ الملفات بإستخدام نظام تسير الملفات FAT. و هذا ما دفع مطويري لينوكس إلى إدخال تعديلات على النواة 2.6.30 لتفادي أي هجوم مسقبلي بخصوص ذلك.

نظام تسيير الملافات FAT يعتبر بديهي و قديم و إستخدامه أصبح محدود، و لكن ورغم ذلك قامت مايكروسوفت بالدفاع عن ملكيتها الفكرية.

ما هي الخلاصة؟
  • توفير إطار برمجي بديل لمنصة دوت نت أمر مهم لأنه يساعد على خلق توافقية أفضل بين مختلف المنصات المتواجدة و ربما قد يشجع البعض على إستخدام لينوكس أو الإنتقال إليه.
  • إستخدام مونو لتطوير برمجيات بلغة السي شارب مع إستخدام واجهة رسومية مفتوحة المصدر ك GTK يبقى إختيار مناسب و لا خوف منه.
  • إستخدام مونو لتعلم لغة سي شارب أو إستخدامه في تطوير البرمجيات الحرة المكملة (التي تقدم خدمات بسيطة) يبقى إختيار شخصي و لا خوف منه تقريبا لانه يسهل إستبدالها ببرمجيات أخرى في حالة نزاع.
  • أي إستخدام لمونو لتطوير مكتبات و برمجيات أساسية سيتم إعتمادها لتطوير مكوانات و برمجيات أساسية كواجهة مكتبية أو حزمة مكتبية مثلا يعتبر مجازفة حقيقية قد تحمل عواقب وخيمة في المستقبل.

هل ستنتهي هذه الأخبار و المخاوف يوما ما؟
لن تزول المخاوف حتى أن تقوم مايكروسوفت بإحدى الخطوات التالية:
  • ترخيص منصة دوت نت تحت رخصة حرة كـ جيبيئل GPL 3
  • الإعلان بشكل رسمي أنها لن تقوم بملاحقة المبرمجين الذي يستخدمون هذه التقنيات في البرمجيات الحرة و المفتوحة المصدر.
تحديث 07/07/2009: أخبرت مايكروسوفت أنها ستعلن على أن تشمل C# و CLI في وعدها للمجتمع (Community Promise). و هو وعد سبق و أن قدمته للمجتمع بعدم ملاحقة من يستخدم بعض تقنيات مايكروسوفت لتطوير البرمجيات دون أي ترخيص. لا يحل هذا كل الخلاف (على ما أعتقد) لكنها خطوة جيدة تشكر عليها.

روابط إضافية:
الأسئلة الأكثر تكرار حول ترخيص مونو.
صفحة الملكية الفكرية و الترخيص لمايكروسوفت.
لماذا لا يجب علة البرمجيات الحرة ان تعتمد على مونو أو سي شارب C#
مشروع مونو.

يونيو 24، 2009

لمحبي تبريد المعالج بالماء، لم لا تضع الحاسوب بأكمله في حوض أسماك؟


شاهد الفيديو بنفسك ليزول العجب :)




ذلك السائل يسمى بالزيت المعدني و هو غير موصل للتيار الكهربائي.
فكرة ممتعة للتخلص من صوت المراوح و الحرارة الناتجة و لإضفاء جمالية على الحاسوب و مكان العمل :)

يونيو 21، 2009

مقارنة بين أداء بايثون و لغات البرمجة الأخرى

قضيت الفترة الأخيرة في إختبار أداء بايثون خصوصا أداء الحلاقات التسلسلية for و مقارنته بكل من روبي (Ruby)، بيئتشبي (PHP)، جنوا سي بلاس بلاس (GNU C++)، سي شارب (C#)، جافا (Java) و سكالا (Scala)

عند تعلمي لبايثون لاحظت أن مرونته و أدائه جد قويين في مجموعة من المهام، من بينها إنشاء قاموس يحتوي على 1 مليون مفتاح و قيمة في ثانية واحدة و أشياء أخرى. و أثناء حلي لمشاكل المشروع Euler Project لاحظت بعض البطء في الحلاقات التسلسلية for لكن لم أعر الأمر أي اهتمام لأن حاسوبي يعتبر من الديناصورات (P4 2.4Ghz) و عند تجربتي لنفس الكود على حاسوب آخر (Core 2 Duo 2.4Ghz) كان ينجز نفس المهمة 3 مرات أسرع.

و بعد وضعي للمشكلة رقم 5 تفضل الصديق محمد الجوهري بوضع الحل بلغة C# و عند تجربتي لحله تفاجأت من السرعة التي يتم العثور بها على الحل. قرأت الكود و جربته أكثر من مرة محاولا العثور على شيء يميزه، لكنه عادي. من هنا انطلقت رحلتي لفهم ما يجري في الحلاقات التسلسلية for في بايثون 2.6.2

الكود الاول:
في البداية كان الكود كالتالي و يستغرق 55 ثانية ليجد الحل:
n = 20
divs = [x for x in range(n, 0, -1)]
i = 0

while True:
    i = i+1
    nop = False
    for x in divs:      
        if (i*n) % x != 0:
            nop = True
            break

    if nop == False:
        print "\nThe answer is ", i*n
        break

هذا الكود رديء، و غيرته ليصبح كالتالي و هو يستغرق 40 ثانية:
i = 20
done = False
seq = range(2, 20+1)

while not done:
    for j in seq:
        if i % j != 0:
            break
        elif j == 20:
            done = True

    i += 20

print i-20

ثم قرأت حول طرق تحسين كود بايثون و وجدت من ينصح باﻹستخدام الدوال التالية lambda, map و filter بدلا من الحلقة التسلسلية for و كانت النتيجة كالتالي:

الكود الثالث يستغرق 5 دقائق و 34 ثانية:
i = 20
done = False
seq = range(2, 20+1)

while not done:
    if len(filter(None, map(lambda y: i % y == 0, seq))) == len(seq):
        done = True
        break
    i += 20
  
print i

الكود الرابع يستغرق هو أيضا 5 دقائق و 34 ثانية:
i = 20
done = False
seq = range(2, 20+1)

while not done:
    if False in map(lambda x: i % x == 0, seq):
        pass
    else:
        done = True
        break
    i = i + 20

print i

الكود الخامس: ثم بعد ذلك قمت بإدراج الكود الثاني داخل دالة و أصبح على الشكل التالي و يستغرق 24 ثانية:

def euler5():
    i = 20

    seq = range(2, 20+1)
    while True:
        for j in seq:
            if i % j != 0:
                break
            elif j == 20:
                return i

        i += 20

print euler5()



المهم ماذا يجري هنا؟ و لما كل هذا؟
بايثون يعتبر من لغات البرمجة التي تعتمد على التحديد الدينامكي أو المرن للمتغيرات (Dynamically Typed)، بمعنى أن المتغيرة a يمكن أن تحتوي على قيمة رقمية ثم تتحول لتعبر عن قيمة نصية بكل سهولة أثناء عمل البرنامج. و هذا ما يتشابه فيه كل من بايثون python، روبي ruby و بيئيتشبي php. بينما تعتمد كل من لغة سي بلاس بلاس c++ و جافا java و سي شارب c# و سكالا Scala على التحديد الثابت للمتغيرات (Statically Typed). طبعا هنا أقوم بشرح مبسط كما لم أتطرق للأفضلية لأن لكل منها (الغات) نقاط قوتها و ضعفها.

المهم هو أن هذه المرونة تتم على حساب جزء بسيط في ضعف الاداء في بعض العمليات. لكن المثير هو أن ضعف أداء الحلاقات التسلسلية for أكبر بكثير من المتوقع، فما هو السبب؟

اتضح لي فيما بعد أن الفلسفة التي يتبعها مطورو بايثون هي:
1. سهولة قراءة و وضوح الكود أهم من تعقيده لأجل تحسينه (optimization) للإستفادة من أخر جزء من الثانية.
2. هنالك قانون يسمى قانون مور (Moore's law) يقول أن كفائة العتاد تتضاعف كل 18 شهر تقريا. بمعنى أنه مع تطور العتاد سيسبح الفرق بسيطا بين الكود المُحسن و العادي.
3. و إذا كانت السرعة أولوية لا غنى عنها حينها يجب على المبرمج أن يستخدم قاعدة 90/10 بحيث يُفضل أن يكتب الجزء المسرع/المحسن بلغة C أو لغة أخرى.


النقطة المهمة التي تعجبني في مشاكل المشروع يولر Euler Project هي أن كل مشكلة تقريبا يمكن حلها بطريقة تقليدية و أخرى بإستخدام بعض الذكاء و التفكير مع مراعات أن يبقى الحل بسيطا :)
و كما قال لِيُوناردو دا فينشي (Leonardo da Vinci) "البساطة هي منتهى التعقيد"

و هذا هو ما قمت به في الحل الثاني للمشكلة رقم 5 بحيث تظهر النتيجة في جزء من الثانية.


لكن كيف هو أداء باقي لغات البرمجة الأخرى في إيجاد الحل للمشكلة رقم 5؟
1. روبي Ruby 1.8.7 أوجد الحل في دقيقتين و ثلاثين ثانية (2min 30s):
def GetResult()
    n = 20
    i = n
    while true do
        for j in 2..n do
            break if i % j != 0
            if j == n
                return i
            end
        end
        i += n
    end
end

puts GetResult()

ثم بعد تعديل الحلقة التسلسلية for أوجد الحل في دقيقتين و ثانية (2min 1s)
def GetResult()
    n = 20
    i = n
    seq = 2..n
    while true do
        for j in seq do
            break if i % j != 0
            if j == n
                return i
            end
        end
        i = i+n
    end
end

بيئيتشبي PHP 5.2.9 أوجد الحل في 21 ثانية:
$i = 20;
$n = $i;
$Done = false;
while (! $Done) {
    for ($j = 2; $j <= $n; ++$j) {
        if ($i % $j != 0) { break; }
        else {
            if ($j == $n) { $Done = true; }
        }
    }
    $i = $i + $n;
}

print $i - $n . "\n";

من خلال ما سبق يتضح أن php أسرع من python و ruby. و كلها تصنف كلغات ديناميكية النوعية.

لكن كيف هو أداء اللغات الثابتة النوعية ك C#, Scala و GNU C++ ؟ الجواب هو إنها فائقة السرعة مقارنة مع اللغات الديناميكية المجربة أعلاه.

بالنسبة لجنوا سي++ (GNU C++) أوجد الحل في ثاتية و نصف!:
#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    int i = 20;
    bool Done = false;
    while (!Done) {
     for (int j = 2; j <= 20; ++j)
     {
         if (i % j != 0) break;
         else
         {
            if (j == 20) Done = true;
         }        
     }
     i += 20;
    }
   
    cout << endl << i-20 << endl;
    return EXIT_SUCCESS;
}

بالنسبة لسي شارب C# أوجد الحل في ثانيتين. (بإستخدام كود الصديق محمد الجوهري)

بالنسبة لجافا (java) أوجدت الحل في ثانية و ثمانية أعشار الثانية (1.8s)
public class Main {
    public static void main(String[] args) {
        int i = 20;
        boolean Done = false;
        while (!Done) {
            for (int j = 2; j <= 20; ++j) {
                if (i % j != 0) {
                    break;
                } else {
                    if ( j == 20) {
                        Done = true;
                    }
                }
            }
            i=i+1;
        }

        System.out.println(i-1);
    }
}

و أخيرا لغة سكالا (Scala) التي أوجدت الحل في ثانيتين و أربعة أعشار الثانية (2.4s)
def euler5(): Int = {
  var n = 20
  var i = n
  var done = true
  while (done)
  {
    var j = 2
    var iter = true
    while (iter && j < n+1)
    {
      if (i % j != 0) iter = false
      else j += 1
    }
    if (iter == true) done = false
    i += n
  }
  i-n
}

println(euler5())

كما نلاحظ فإن اللغات دات التحديد الثابت تعرض الحل في حدود ثانيتين، بينما اللغات دات التحديد الديناميكي تسغرق بعض الوقت لتصل إلى النتيجة. هذه الفرق عند إنجاز بعض المهام أو في بعض الحالات قد لا يعجب البعض، لكن في أغلب الأحيان لن تواجهوا هذا النوع من المتطلبات (السرعة أولا و أخيرا) و ستجدون في اللغات دات التحديد الديناميكي المرونة التي ستسمح لكم بتطوير برمجياتكم بسرعة أكبر و مدة أقصر. لكن إن صممت يمكن إعتبار Scala بديل أفضل لأنها تجمع بين مجموعة من المزايا و أنماط البرمجة.

الخلاصة:
1. أكتب دائما كود بسيط و تسهل قرائته.
2. الحلاقات التسلسلية for تستهلك الكثير من وقت المعالج، و يمكن تحسينها بإتباع بعض النصائح.
3. إدا كانت السرعة جد ضرورية في منطقة معينة من برنامجك حينها قم ببرمجة ذلك الجزء بلغة سي أو سي ++
4. سيحصل بايثون على آلة إفتراضية محسنة (LLVM) ستجعل أداءه مشابه للغة سي و سي++


تحديث 1: قمت بتجربة الكود الخامس بإستخدام الإصدار الجديد لبايثون 3.1 الذي توصل إلى الحل في 32 ثانية. (مازل أبطأ في هذا الإختبار لكن أفضل من الإصدار 3.0)

يونيو 14، 2009

مشروع Euler project: المشكلة رقم 10

المشكلة رقم 10:
مجموع العداد الأولية تحت 10 هو: 2 + 3 + 5 + 7 = 17

المطلوب:
أجد مجموع كل الأعداد الأولية تحت مليونين.

الحل:
import math

def isPrime(n):
    nbrs = [2] + range(3, int(math.sqrt(n))+1, 2)   
    for i in nbrs:
        if n % i == 0:
            return False
    return True

def sumPrimes(n):
    primes = [2] + [x for x in range(3, n, 2) if isPrime(x)]
    return sum(primes)

print sumPrimes(2000000)

الشرح:
1. نستدعي وحدة الرياضيات math بواسطة التعليمة import
2. نكتب دالة isPrime وظيفتها إختبار العدد الذي تتوصل به كمعيار n هل هو أولي أم لا. ذاخل هذه الذالة ننشئ قائمة بكل العداد بداية من 2 حتى جدع تربيع العدد n مع تفادي كل مضاعفات العدد 2
3. نكتب دالة وظيفتها إنشاء قائمة primes بكل الأعداد من 2 حتى n مع إجتناب مضاعفات العدد 2 و بشرط أن يكون أوليا، ثم بعد ذلك نستخدم الدالة sum حتى تحسب مجموع أعداد هذه القائمة.
4. يتم عرض النتيجة بإستخدام print

يونيو 13، 2009

مشروع Euler project: المشكلة رقم 9

المشكلة رقم 9:
تتألف ثلاثية فيثاغورس من الأعداد الصحيحة a < b < c بحيث تحقق العلاقة a2 + b2 = c2
مثال: 3^2 + 4^2 = 9 + 16 = 25 = 5^2

المطلوب:
توجد تحديدا ثلاثية فيثاغورس واحدة تكون فيها a + b + c = 1000
أجد abc

الحل الأول:
def pytha_Triplet(n):
    for a in range(1, n+1):
        for b in range(a+1, n+1):
            for c in range(n-a-b, b, -1):
                if a + b + c == n:
                    if (a**2) + (b**2) == (c**2):
                        return a*b*c

print pytha_Triplet(1000)

الشرح:
1. نقوم بتحديد دالة pytha_Triplet و تأخذ المعيار n. بداخلها يوجد حلقة تسلسلية تبدأ من 1 حتى آخر عدد (قيمة n). بداخلها توجد حلقة أخرى تبدأ من قيمة المتغيرة a+1 (الممثلة للمرحلة التي وصلت إليها الحلقة السابقة) و حتى آخر عدد ( وهو 1000 المعبر عنه ب n). و في داخل هذه الحلقة توجد حلقة أخرى تبدأ تنازليا من قيمة n-a-b حتى تصل إلى قيمة المتغيرة b (الممثلة للمرحلة التي وصلت إليها الحلقة الثانية). ثم بعد ذلك يتم إختبار مجموع a+b+c هل يتساوى مع n. إذا كان الشرط صحيحا يتم إجراء إختبار ثاني لمعرفة هل قيمة المتغيرتين a أُس 2 + b أُس 2 يتساوين مع قيمة المتغيرة c أُس 2. إدا كان الشرط صحيحا تخرج الدالة بنتيجة قيمة a*b*c
2. يتم عرض نتيجة الدالة pytha_Triplet

> كما تلاحظون هذه الحل يعتمد على طريقة تقليدية للعثور على ما نريد و هو يهدر الكثير من وقت المعالج.

الحالي الثاني (أسرع):
def pytha(n):
    a, b, c = 1, 2, n-3
    while (a < n/3):
        if a**2 + b**2 == c**2:
            return a*b*c
        elif c-1 > b+1:
            a, b, c = a, b+1, c-1
        else:
            a, b, c = a+1, a+2, n-(a+1)*2-1

print pytha(1000)

الشرح:
1. نكتب ذالة pytha و تأخد n كمعيار. بذاخلها يوجد:
2.1. يتم تعين قيمة 1 للمتغيرة a، و قيمة 2 للمتغيرة 2 و قيمة n-2 للمتغيرة c في آن واحد.
2.2. نحتاج إلى حلقة شرطية تبقى تدور ما دامت قيمة المتغيرة a أصغر من ثلث قيمة n. لماذ!؟ لأن ثلث قيمة n هو 333 و إدا كانت a = 333 فإن بالضرورة على b أن تكون أكبر من a بمعنى أنها على الأقل يجب أن تكون 334 و إذا كانت b = 334 فبالضرورة أن تكون قيمة c أكبر من b و بذلك فإن أصغر قيمة ممكنة ل c في هذه الحالة هو 335. و إذا قمنا بحساب مجموع a+b+c سنحصل على 1002 و بذلك فإدا وصلت قمية المتغيرة إلى ثلث قيمة n على الحلقة الشرطية بالخروج.
2.3. يتم إختبار قوة a في 2 + قوة b في 2 هل تتساوى مع قوة c في 2. إدا كان الشرط صحيح تخرج الدالة بمجموع ضرب قيمة a*b*c
2.4 إدا كان الشرط خاطئا يتم إختبار هل c-1 ما زالت أكبر من قيمة b+1. إدا كان الشرط صحيحا تبقى قيمة المتغيرة على حالها و تزيد قيمة b بـ 1 و تنقص قيمة c بـ 1 ثم تمر الحلقة إلى الدورة التالية.
2.5 أما إذا كان الشرطين السابقين خاطئين يتم تحديث قيمة a لتساوي a+1. ثم تصير b تساوي قيمة a+2 و قيمة c تساوي n ناقص قيمة (a+b) المعبر عنها بـ (a+1 مضروبة في 2) ناقص 1
3. يتم عرض نتيجة الدالة pytha بواسطة print

يونيو 12، 2009

مشروع Euler project: المشكلة رقم 8

المشكلة رقم 8:
أجد أكبر قيمة عددية مكونة من خمسة أرقام متتابعة في هذه السلسلة المكونة من 1000 رقم:

73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450

الحل:
nbrs = """73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450"""

nbrs = nbrs.replace('\n','')
product = 0

for i in range(len(nbrs)-4):
    p = 1

    for i in nbrs[i:i+5]:
        p *= int(i)

    if p > product:
        product = p

print product

الشرح:
1. المتغيرة nbrs تحتوي علة كل الأرقام لكن بصفة نصية. لاحظ أنها بين """. كما أن الأرقام كتبت موزعة على عدد من الأسطر و بالتالي في إن كل سطر يعبر عنه بحرف خفي يعبر عنه ب '\n' و يجب التخلص منه.
2. نتخلص من حرف '\n' من خلال تعويضه بالفراغ nbrs.replace('\n','')
3. نقوم بأخد و إختبار قيمة كل خمسة أرقام متتالية في تلك السلسلة من الأرقام. ثم نحتفظ بأعلى قيمة ناتج عملية ضرب تلك الارقام في بعضها البعض في المتغيرة product
4. بعد الإنتهاء من تلك السلسلة يتم عرض أعلة قيمة ناتج عثرنا عليها.

يونيو 11، 2009

مشروع Euler project: المشكلة رقم 7

المشكلة رقم 7:
من خلال عرض قائمة بالأعداد الأولية الستة الأولى: 2 ، 3 ، 5 ، 7 ، 11 و 13، نرى أن العدد السادس في القائمة هو العدد الأولي 13.

المطلوب:
ما هو العدد الأولي المرتب 10001 في قائمة الأعداد الأولية؟

الحل:
import math

def isPrime(n):
    nbrs = [2] + range(3, int(math.sqrt(n))+1, 2)   
    for i in nbrs:
        if n % i == 0:
            return False
    return True

def findPrime(position):
    i = 1
    counter = 1 # 1 instead of 0 because 2 won't be tested
    while True:
        i += 2
        if isPrime(i):
            counter += 1
        if counter == position:
            return i

print findPrime(10001)

الشرح:
1. نقوم بإستدعاء الوحدة math  التي تضم دوال العمليات الرياضية.
2. نقوم بتحديد دالة isPrime التي ستقوم بإختبار العدد المعطي في المعيار (n) هل هو اولي أم لا. و تقوم بذلك من خلال إنشاء قائمة بكل الأعدد التي هي أصغر من قيمة (n) حتى تجري عملية القسمة علىها باحثتا عن عدد لا يقبل القسمة إلا على نفسه. و حتى يتم تسرع عملية البحث يتم إستخدام جدع تربيع قيمة العدد (n) بالإضافة إلى تخطي كل العداد التي تقبل القسمة على 2
3. إنشاء دالة findPrime لإيجاد العدد الاولي صاحب الرتبة 10001 في قائمة الأعداد الأولية. تقوم هذه الدالة بالبحث عن العدد صاحب الرتبة المطلوبة (position) و ذلك من خلال الدوران في الحلقة الشرطية while. في كل دورة يتم إختبار عدد جديد، إذا كان أولي يتم تحديث العداد counter ثم إختبار الرتية اتي وصلنا إليها، و إذا كانت هي الرتبة المناسبة يتم الخروج من الدالة بالنتيجة المخزنة في المتغيرة i.
4. يتم عرض النتيجة بواسطة print


كما تلاحظون فقد إستخدمت ما تعلمناه في تجربتنا الأخيرة في تحسين كود بايثون، حيث إستخدمنا الدوال بدلا من كتابة الكود في الجزء العام بالإضافة إنشاء القوائم range خارج الحلاقات التسلسلية.

يونيو 10، 2009

مشروع Euler project: المشكلة رقم 6

المشكلة رقم 6:
مجموع مربع الأعداد الطييعية العشرة الأولى هو:
1^2 + 2^2 + ... + 10^2 = 385

و مربع مجموع الأعداد العشرة الطبيعية الأولى هو:
(1 + 2 + ... + 10)^2 = 55^2 = 3025

و الفرق بين النتيجتين هو:  3025 - 385 = 2640


المطلوب:
أجد الفرق بين مجموع مربع الأعداد الطبيعية المئة الأولى و مربع جمعها.


الحل الأول:
def sumSquares(n):
    r = 0
    for i in range(1, n+1):
        r = r + (i ** 2)
    return r

def squaresSum(n):
    r = 0
    for i in range(1, n+1):
        r = r + i
    return (r**2)

print  squaresSum(100) - sumSquares(100)
الشرح:
1. نخصص دالة لحساب مجموع مربع كل عدد إسمها sumSquares() بحيث تأخد المعيار (Parameter) n و تستخدم قيمته كأعلى عدد في سلسلة الأعداد 1 إلى n. ثم بعد ذلك نستخدم حلقة تسلسلية لحساب تربيع كل عدد (i**2) في السلسلة ثم إضافة الخارج على المجموع r. و بعد الإنتهاء من الحلقة تخرج الدالة بالنتيجة المخزنة في r.
2. الدالة الثانية squaresSum() تحسب تربيع مجموع الأعداد. و هس تشبه الدالة الأولى في التركيبة غير أن النتيجة مختلفة.
3. ثم نقوم بعرض النتيجة مستخدمين print التي تقوم بإستدعاء الدالة الاولة و الثانية ثم تعرض فرق النتيجة.

ملاحظة: إستخدام علامة النجمة مرتين ** يفيد حساب مربع عدد ما.

الحل الثاني:
كما تفضل الصديق أحمد يوسف في حله، يمكن كتابة الحل في سطر واحد:
print  sum(range(100+1))**2 - sum(x**2 for x in range(100+1))

الشرح:
1. يتم إنشاء قائمة تحتوي على سلسلة من الأرقام تبدأ من 0 إلى 100 ثم يتم حساب مجموع الأرقام في هذه الأرقام على الشكل التالي 0+1+2+3..+100 ثم يتم حساب مربع هذا المجموع.
2. يتم إنشاء قائمة تحتوي على مئة و واحد عنصر (0 إلى 100)، كل عنصر هو عبارة عن عدد كان أصله هو مربع رتبته في القائمة، بمعنى 0^2 و 1^2 و 2^2 ... إلى 100^2. ثم يتم حساب مجموع هذه الأعداد بواسطة الدالة sum() تماما كالجزء الأول.
3. بعد ذلك تقوم print  بعرض فارق المجموعين.

نعم، هذا الحل من حلول النينجا Python Ninja :)

يونيو 09، 2009

مشروع Euler project: المشكلة رقم 5

المشكلة رقم 5:
العدد 2520 هو أصغر عدد يمكن أن يقسم على كل عدد بدءا من 1 إلى 10 دون أي باقي.

المطلوب:
ما هو أصغر عدد يمكن قسمته على كل الأعداد من 1 إلى 20 دون أن يكون هنالك باقي (القسمة بالتساوي)


الحل الأول (إستغرق 24 ثانية على حاسوبي):
def euler5():
    i = 20
    seq = range(2, 20+1)
    while True:
        for j in seq:
            if i % j  !=  0:
                break
            elif j == 20:
                return i

        i += 20


print euler5()
الشرح:
1. نستخدم الكود داخل دالة حتى تزيد من سرعة الأداء. الدالة تم تحديدها بواسطة الكلمة المفتحية def يليها إسمها euler5 المتبوع ب () ثم :

2. المتغيرة i هي التي ستتزايد قيمتها تصاعديا حتى تصل إلى الرقم الذي يمكنه القسمة على جميع الأعداد من 1 إلى 20
3. المتغيرة seq هي قائمة بالأرقام التي سيتم إستخدامها كقاسم. القائمة تحتوي على كل الأعداد من 2 إلى 20
4. الحلقة شرطية while. و بالصيغة التي كُتبت بها فستبقى تدور إلى الأبد أو حتى يتم كسرها بتعليمة break أو return

5. الحلقة التسلسلية for التي تدور من أول عدد في القائمة seq إلى آخر عدد فيها. في كل دورة تأخد المتغير j قيمة العدد التالي من القائمة
6. الجملة الشرطية if التي تقوم بإجراء القسمة لإختبار قيمة الباقي هل هي 0 أم لا. إدا كان الباقي (و ليس الخارج) لا يساوي 0 يتم كسر الحلقة for بواسطة التعليمة break و ذلك لنختصر المسافة لأنه لا دعي لإختبار كل الأعداد المتبقية في القائمة seq إن كان العدد الذي نحن بصدده باقي قسمته لا بساوي 0. بمعنى ليس قاسما طبيعيا. و بعد دلك ينتقل الكود للسطر الذي يحتوي على i += 20 حتى يتم الصعود بقيمة 20 في كل دورة من دورات الحلقة while.
7. أما إدا كانت كل الأعداد المتواجد في القائمة seq تقبل القسمة بشكل طبيعي على قيمة المتغيرة i، فبالضرورة إدن أن قيمة المتغيرة j ستكون مساوية ل 20 و ذلك لأنه آخر رقم في القائمة قابل للقسمة بشكل طبيعي. بمعنى أننا إجتزنا كل الأعداد في القائمة حتى وصلنا إلى 20. و بعد التأكد من ذلك نخرج من الدالة euler5() بنتيجة المتغيرة i و تم عرضها من طرف الدالة print


الحل الثاني (يتوصل إلى النتيجة بشكل آني):
def isPrime(value):
    for i in range(2, value):
        if value % i == 0:           
            return False
    return True


def sumMultiply(seq):
    r = 1
    for i in seq:
        r = r * i
    return r


def findDivisible(value, seq=[]):
    multiplier = 1   
    while True:
        for i in seq:
            if (value * multiplier) % i != 0:
                multiplier += 1
                break
            elif i == seq[-1]:
                return (value * multiplier)


nbr = 20
divs = [x for x in range(nbr, 1, -1)]
primes = sumMultiply(filter(isPrime, divs))

print findDivisible(primes, divs)

الشرح:
يبدو و كانه صعب لكنه سهل :)

1. قمنا بإضافة دالة isPrime(value) التي ستقوم بمعرفة هل العدد الذي حصلت عليه من المعيار value أهو عدد أولي ام لا. هذه الدالة سيتم إعتمادها و تحسينها في مشاكل مستقبلية.
2. دالة sumMultiply(seq) تقوم بإعطا الخارج بعد قيامها بعملية ضرب كل أعداد القائمة seq في بعضها البعض.
3. دالة findDivisible(value, seq=[]) تقوم بالبحث عن أول قاسم للأعداد التي توصلت بها من القائمة seq.

فكرة هذا الحل هو إيجاد الأعداد الأولية في قائمة الأعداد من 2 إلى 20 ثم إجراء عملية ضرب بعضها في بعض، و العدد الذي نحصل عليه من هذه العملية يتم إستخدامه كأساس/كمنطلق يتم إستخدامه للبحث عن مضاعف له يقبل القسمة على كل الأعداد من 2 إلى 20. و هذا هو ماتقوم به الأسطر الأخيرة.

يونيو 08، 2009

مشروع Euler project: المشكلة رقم 4

المشكلة رقم 4:
العدد البليندرومي (Palindromic number) هو العدد الذي يمكن فراءته من كلى الجهتين.

أكبر عدد بليندرومي ناتج من عددين مكونين من رقمين هو : 9009 = 91 x 99


المطلوب:
ابحث عن أكبر عدد بليندرومي ناتج من عددين مكونين من ثلاثة أرقام.


الحل الأول:
def palindromic():
    for i in range(999, 900, -1):
        for j in range(999, 900, -1):           
            n = i * j
            s = str(n)

            if s == s[::-1]:
                return n


print palindromic()

شرح الحل الأول:
1. سنقوم بكتابة دالة إسمها ()palindromic مستخدمين الكلمة المفتحية def المخصصة للتعريف الدوال.
2. نستخدم حلقتين متتاليتين تبدأ كل واحدة دورتها من العدد 999 نزولا إلى 900. لاحظ معي هنا أننا أضفنا -1 كمعيار للدالة ()range في كل من الحلقتين لتسمح لهما بالنزول من الأكبر إلى الأصغر.
3. المتغيرة n تساوي مجموع المتغيرة i x j. المتغيرة i تكتسب قيمتها من الحلقة الأولى و j من الحلقة الثانية.
4. نستخدم المتغيرة s لتعبر عن نتيجة المتغيرة n بصيغة نصية. بمعنى آخر نقوم بتحويل قيمة المتغير n من قيمة عددية إلى قيمة نصية. مثال إدا كانت قيمة n تساوي 998001 فإن قيمة s ستكون "998001". لاحظ إضافة "". هذه العملية تتم بواسطة الدالة ()str
5. نقوم بمقارنة قيمة المتغيرة s بقيمة عكسية. مثال: "998001" تصبح "100899". أية متغيرة نصية عندما تستخدم على الشكل s[::-1] ينتج عنها قيمة عكسية كما رأينا.
6. ثم في النهاية إدا عثرنا على عدد باليندرومي يتم الخروج به كنتيجة للدالة ()palindromic و من ثم  عرضه من طرف print


الحل الثاني:

print  max(x*y for x in range(999, 900, -1) for y in range(999, 900, -1) if str(x*y) == str(x*y)[::-1])

شرح الحل الثاني:
هنا نقوم بنفس الشيء كما الحل الأول لكن في سطر واحد فقط.
1. نقوم بإستخدام حلقة داخل حلقة. for x in range(999, 900, -1) for y in range(999, 900, -1)

هذا الإجراء يفترض أن يقوم بإنشاء قائمة مكونة من جميع قيم x*y
2. لكن نحن لا نريد قائمة بكل القيم بل فقط القيم التي يمكن أن تتطابق بصيغة عدد باليندرومي. يتم ذلك بإستخدام الجزء الشرطي if str(x*y) == str(x*y)[::-1])
3. عند تجميع كل الأعداد الياليندرومية في القائمة يتم عرض أعلى قيمة حصلنا عليها و ذلك بواسط الدالة max


هل من مبرمج بلغة روبي يمكن ان يكتب الحلول مستخدما تلك اللغة الجذابة؟

يونيو 07، 2009

سلسلة بايثون للمبتدئين - 01

سواءا سمعت العالم كله يتحدث عن لغة البرمجة بايثون (python) و أردت أن تعرف عنها المزيد و ربما أردت تعلمها لكن لا تريد أن تخسر المزيد من شعر رأسك محاولا تعلم لغة جديدة، أو أنك تريد تعلم لغة برمجة مرنة و قوية تصلح للعامة و لا تتطلب منك أن تكون متخصصا، أو أنك تريد تعلم لغة برمجة تعمل على مجموعة من المنصات و تسمح لك بالتركيز على المهمة التي تريد إنجازها بدلا من ملاحقة الأخطاء الناتجة عن نسيان نقطة فاصلة في أخر سطر أو مزدوجة { أو قوص )، فستجد في لغة بايثون كل هذا و أكثر. و ستجد في هذه التدوينات كل الخطوات التي ستسمح لك باكتساب المهارات الأساسية بشكل عملي، بسيط و سريع.


1. كيف يمكن الحصول على لغة بايثون؟
لغة بايثون مفتوحة المصدر (بإمكان كل فرد أن يساهم في تطويرها) و هي مجانية يمكن تحميلها من الشبكة و تثبيتها كأي برنامج عادي. و هي متوفرة على منصة ويندوز، ماك و لينوكس. يمكن تحميلها من هنا.

ملاحظة 1: بايثون مثبت بشكل افتراضي على أغلب توزيعات لينوكس و على نظام ماك.


2. قمت بتثبتها، ثم ماذا بعد؟
كل ما تحتاجه هو تشغيل محرر IDLE المرفق مع لغة بايثون لتبدأ البرمجة.


3. أسسيات الكتابة بلغة بايثون:
  • يفضل أن تكتب دائما بالحروف اللاتينية الصغرى a,b,c لأن بايثون يميز بين الحروف الصغيرة و الكبيرة A,B,C. و بالتالي فإن كل من Name و name و NAME ترمز إلى محتوى مختلف.

  • يتم إستخدام مفتاح : من أجل الانتقال إلى كتابة جزء من الشفرة/الكود الخاص بمهمة/قسم معين. و مباشرة بعد الضغط على مفتاح Enter  (بعد كتابة :  ) ستلاحظ أن المحرر تحرك بنفس مسافة مفتاح Tab للإشارة إلى أنك دخلت جزء جديد من الشفرة. لا تقلق سيتضح لك هذا الأمر فيما بعد.

  • هنالك بعض الكلمات المفتحية (Keywords) المحجوزة التي يجب عليك ألا تستخدمها أثناء تعريف المتغيرات.


4.كلمات مفتحية، أجزاء كود، تفريق بين حروف صغيرة و كبيرة، يبدوا أنني سأتوقف هنا.
انتظر!! قم بتحرير هذا السطر على المحرر التفاعلي IDLE:

print  "Hi, this is my first hello world using python"

رأيت، لقد قمت بعرض أول رسالة نصية :)



الأساسيات:

جيد، الآن سنبدأ بتعلم بايثون :)

قم بتحرير:
5 * 5

ثم:
160 - 3

ثم:
200/10

كما ترى إجراء العمليات الحسابية بسيط للغاية. ماذا عن الرسائل النصية؟
"I Love " + "Python!"
لقد قمنا بعرض رسالة مكونة من جزأين.


ماذا عن:
"7" * 3
النتيجة هي "777"

الآن حرر:
"777" - 7
نعم، حدث خطأ و ظهرت لك رسالة باللون الأحمر. ستتضح لنا الأمور بعد قليل.

في الأمثلة التي قمنا بتحريرها نلاحظ أحيانا استعمال "" و أحيانا لا. ما هو الفرق؟
عند إستخدام "" نقول لبايثون أن ما يجد بينهما هو محتوي نصي. فمثلا استخدمنا "I Love" و هي محتوي نصي، و نستنتج ذلك بكل بداهة. بينما عند إستخدام "777" فنحن نعرف أنه عدد لكن و رغم كونه كذلك في أعيننا إلا أنه محاط بـ "" مما يجعل بايثون يتعامل معه كنص.

> لذلك عندما تريد عرض أو التعامل مع المحتوى النصي يجب أن نحيطه بـ "" و المحتوى العددي يكتب بدونها.


ماذا عن العمليات الحسابية؟
بين الأعداد يمكن إستخدام علامة + - / * و علامات أخرى سنتعرف عليها عندما نحتاجها.
و بين المحتوى النصي يجوز إستخدام + بين محتوى نصي و آخر: "I love" + " Python!"
و علامة * لتكرار نفس المحتوى عدد المرات التي تريد: "Hello " * 5
النتيجة هي: "Hello Hello Hello Hello Hello"


المتغيرات:

الآن، ماذا إذا كنا نريد أن نحتفظ بقيمة معينة من أجل إستخدامها في أكثر من مكان؟  ماذا لو أردنا أن نعطي لأية قيمة - سواءا كانت رقمية أو نصية أو أي شيء أخر - اسم يرمز إلى تلك القيمة مثلا كأن نقول pi=3.14 ؟

هذا هو ما يسمى بالمتغيرات في لغات البرمجة بحيث يسمح لك بتعريف أية قيمة بإسم تختاره أنت و هو بالتالي سيعبر عن تلك القيمة في كل مرة تستخدمه. كما تسمى بالمتغيرات لأن نفس الإسم الذي اختره يمكن أن تتغير قيمته حسب رغبتك أنت.

ملاحظة: من الناحية التقنية نعلم أن للحاسوب ذاكرة يخزن فيها المعلومات (سواءا بصفة مؤقتة أو دائمة). في الواقع عندما نستخدم متغيرة يتم حجز مكان من ذاكرة الحاسوب لتخزين القيمة بصفة مؤقتة.


بالنسبة لما يجب أن تتذكره بخصوص المتغيرات في بايثون هو كالتالي:
  • يجب أن يكون لها إسم لم يسبق أن تم إستخدامه (ليس شرطا و لكن يفضل أن يكون وحيدا أو مميزا عن باقي الأسماء)
  • ألا يكون الإسم من بين الكلمات المفتحية الخاصة ببايثون.

طرقية الإستعمال هي كالتالي:
name = "Ahmed"
age = 26
كما تلاحظ نكتب الإسم ثم علامة = ثم القيمة (إن كانت نصية فيجب أن تكون بين "" و إن كانت عددية يكفي أن نكتب العدد مباشرة.

الآن ماذا نفعل إن أردنا أن نعرض محتوى المتغيرة؟
نستعمل print لعرض محتوي المتغيرة. مثال:
print  name
print  age

أو
print  12 * 3
print  45 / 5

و يمكن عرض أكثر من متغيرة في سطر واحد من خلال التفريق بينهم بالفاصلة. مثال:
print  "Your name is", name
print  "You are", age
أو
print  "Your name is", name, "and you are", age


الآن، ماذا لو كنا نريد أن نحصل على معلومة من المستخدم، كأن يدخل إسمه؟
في هذه الحالة نستخدم raw_input، مثال:
name = raw_input("Your name please: ")
print "Welcome back", name

أو
age = raw_input("Your age please: ")
print "You are", age

raw_input() تقوم بعرض رسالة إلى المستخدم و تنتظر منه أن يدخل المعلومة. و بعدها يتم تخزين نتيجة هذه العملية في المتغيرة التي تسبق raw_input()

ملاحظة: تعتبر raw_input() من الدوال لأنها بعد الإنتهاء من عملها تخرج بنتيجة معينة (قيمة متغيرة على حسب المعطيات التي عملت بهم الدالة في البداية) سوف نتطرق للدوال فيما بعد :)


هذا كل شيء الآن و لا تنسى أن تطلع على كتاب بايثون :)


ملاحظة: الكلمات المفتحية لبايثون هي كالتالي:
and   elif   if   print   as   else   import   raise   assert   except   in   return   break   exec   is   try   class   finally   lambda   while   continue   for   not   with   def   from   or   yield   del   global   pass

مشروع Euler project: المشكلة رقم 3

المشكلة رقم 3:
العوامل الرئيسية (prime factors) للعدد 13195 هي 5، 7، 13 و 29.

المطلوب:
ما هو أعلى عامل رئيسي للعدد 600851475143 ؟

الحل:
nbr = 600851475143
i = 1
factor = 0

while i + 1 <= nbr :
   
    i = i + 1
   
    if nbr % i == 0:
        factor = i
        nbr = nbr // i


print  factor

الشرح:
هذه المشكلة تحتاج إلى بعض الوقت من أجل التفكير لإيجاد حل بطرقة مختصرة لأن العدد الذي نتعامل معه أكبر من 600 مليار، و أية خوارزمية (algorithm) عادية ستأخد وقتا طويلا.

الطرقة التي إتبعتها هي كالتالي:
  • ابحث عن أول قاسم طبيعي ثم استخدم خارج القسمة كالعدد الذي نبحث له عن العامل الرئيسي.
  • هذه العملية تتكرر في حلقة حتى تستنزف كل الأرقام.
شرح الشفرة المصدرية (كود):
1. نستخدم ثلاثة متغيرات: nbr لتعبر عن العدد المعطى لنا في البداية، i التي سنستخدمها كقاسم، ثم factor التي ستحتوي على أعلى عامل رئيسي.
2. نستخدم الحلقة الشرطية while لاستنزاف كل الأرقام و العوامل الرئيسية.
3. i = i+1 فكل دورة من دورات الحلقة تتزايد قيمة المتغيرة i بـ 1
4. إدا كانت قيمة i كقاسم طبيعي لقيمة المتغيرة nbr يتم حفض العامل الرئيسي الذي عثرنا عليه و المعبر عليه بقيمة i حاليا في المتغيرة factor، و من ثم إستخدام الخارج  كالعدد الجديد بحيث نقوم بإسناده إلى المتغيرة nbr
5. في النهاية يتم عرض آخر (أعلى) عامل رئيسي توصلنا إليه و المعبر عنه من خلال المتغيرة factor

التسلسل الذي اتبعته الحلقة هو كالتالي:
i= 71     nbr= 8462696833
i= 839   nbr= 10086647
i= 1471 nbr= 6857
i= 6857 nbr= 1

يونيو 06، 2009

مشروع Euler project: المشكلة رقم 2

المشكلة رقم 2:
كل عدد جديد في متتالية فيبوناتشي يتشكل من مجموع العددين السابقين له.

و باستخدام 1 و 2 ستكون 10 العناصر الأولى كالتالي:
1,2,3,5,8,13,21,34,55,89,...

المطلوب:
ابحث عن مجموع الأعداد الزوجية في السلسلة التي لا يتجاوز أكبر عنصر فيها 4 ملايين.

الحل:
a, b = 1, 2
fibsum = 0

while  b <= 4000000:
   
    if  b % 2 == 0:
        fibsum += b

    a, b = b, a + b

print  fibsum

الشرح:
1. نقوم بإستعمال متغيرتين a و b. نعطي للأولى 1 كقيمة و للثانية 2 كقيمة.
2. نستعمل متغيرة بإسم fibsum قيمتها في البداية هي 0 و سنستعملها لتخزين مجموع الأعداد الزوجية التي سنكتشفها عند القيام بحساب متتالية فيبوناتشي.
3. سنقوم بإستخدام حلقة while و هذا النوع من الحلقات يستمر في الدوران حول نفسه ما دام الشرط صحيح. الشرط الذي إستخدمناه هو "ما دامت قيمة b أصغر من 4000000"
4. عند كل دورة من دورات الحلقة يتم التحقق من قابلية قسمة قيمة المتغيرة b على 2، و حيث يكون الباقي هو 0
5. إذا كان الشرط صحيحا تتم عملية جمع قيمة b بمجموع قيمة fibsum ثم تحديث هذه الأخيرة بالنتيجة التي حصلنا عليها من عملية الجمع.
6. في السطر الذي يحتوي على a, b = b, a + b يتم إسناد قيمة المتغيرة b إلى a و إسناد مجموع قيمة a+b إلى b في آن واحد.
7. عند الإنتهاء الحلقة من الدوران (عندما يصبح شرطها خاطئا) يتم عرض النتيجة (قيمة المتغيرة fibsum)


هل توصلتم إلى طريقة أخرى؟

يونيو 05، 2009

مشروع Euler project: المشكلة رقم 1

سنحاول معا أن نتعلم بايثون من خلال إيجاد حلول لمشاكل المشروع Euler Project. في كل يوم سأضع مشكلة جديدة و سأضع الحل الذي توصلت إليه بعد يومين. أرجوا أن يشارك الكل بلغة البرمجة التي يفضلها.

سأكتب دروس مبسطة عن بايثون في نهاية هذا الأسبوع، و أنصح بقراءة 90 صفحة الأولى من كتاب بايثون للصديق أحمد يوسف.


المشكلة رقم 1:
إذا قمنا بجرد كل الأرقام الطبيعية تحت العدد 10 بحثا عن  مضاعفات العدد 5 أو 3 سنجد 3، 5، 6 و 9. و إذا قمنا بحساب مجموع هذه الأرقام سنجد الخارج هو 23.

المطلوب:
قم بحساب مجموع مضاعفات 3 أو 5 تحت العدد 1000.

الحل:
result = 0
for i in range(1, 999+1):
    if i % 3 == 0 or i % 5 == 0:
        result += i

print result

الشرح:
1. سنستعمل المتغيرة result تخزين المجموع. و في الداية ستكون قيمتها تساوي 0
2. علينا أن نبحث عن جميع الأرقام تحت العدد 1000 (من 1 إلى 999) عن مضاعفات 3 أو 5. و لترجمة ذلك إلى لغة بايثون نستعمل for i in range(1, 999+1) و التي ستقوم بالدوران في حلقة تبدأ من 1 و تنتهي قبل الألف بمعنى عند 999.
3. في كل مرحلة من مراحل دوران تلك الحلقة تكون المتغيرة i تمثل قيمة أو رقم المرحلة. بمعنى 1, 2, 3, إلى أن تصل إلى 999. و نحن سنقوم بإختبار قيمة المتغيرة i في كل دورة و نرى هل يكون الباقي يساوي 0 إذا تمت قسمتها على 3 أو 5 قسمة أعداد صحيحة (بمعنى دون إجراء القسمة لحساب الأرقام بعد الفاصلة.)
4. هذا الإختبار إما أن يكون صحيح أو خطأ. إذا كان صحيح نظيف قيمة المتغيرة i إلى المتغيرة result. إذا كانت نتيجة الإختبار خاطئة تكمل الحلقة دورانها إلى أن تجد مجددا قيمة يمكن قسمتها على 3 أو 5 بباق يساوي0
5. بعد الإنتهاء من الدوران على كل قيم الحلقة نقوم بعرض نتيجة المتغيرة result


للمتقدمين في بايثون:
هل هنالك حلا آخر؟ مثلا في سطر واحد؟

الحل في سطر واحد:
print  sum([ i for i in range(1, 999+1) if i%3 == 0 or i%5 == 0])

لماذا لا يفضل البعض مايكروسوفت

1. مايكروسوفت نادرا ما قامت بتطوير برمجياتها من الصفر و أغلبها تم شرائه و تطويره جزئيا.

2. نجاح مايكروسوفت قائم على أساليب احتكارية من الناحية التجارية و التقنية. و لهذا تسمع عن العديد من الدعوات القضائية.

3. أغلب عروضها و معلوماتها للعموم تعتمد على التضليل و إستخدام الأسلوب الذي يعرف تحت إسم "الخوف، عدم اليقين و الشك" أو Fear, uncertainty and doubt.

4. تقوم بتشويه المعايير الموحدة تحت مسمى تمديد الخصائص أو Embrace, extend and destroy.

5. تقوم بإصدار برمجياتها بشكل غير متوافق عمدا لتدفع المستهلكين، أقصد المستخدمين، لشراء إصدارات جديدة. مثال: Office 2003 مع 2007. ابحث على غوغل مستخدما Microsoft "intentionally incompatible"

6. مايكروسوفت حاولت احتكار مستقبل الرسوميات الثلاثية الأبعاد 3D بشكل خطير من خلال مكتبة DirectX  و حاولت إقصاء و التقليل من شأن مكتبة OpenGL المفتوحة المصدر. كما قامت هي و شركتي ATI و nVidia و هما  المصنعتين الأساسيتين لبطائق العروض باللعب بهذا السوق.

7. منصة البرمجيات .net في نظر البعض من أهم التقنيات التي طورتها مايكروسوفت لأنها متكاملة و تسهل عمل المبرمج و هي الرد على Java. و كفكرة في البداية كانت رائعة لكن بعد التطبيق ظهرت بعض الإزعاجات كتعدد الإصدارات (خمسة إصدارات) في مدة قصيرة (ضرورة تأقلم المبرمج). كما يتعين على المبرمج أن يحدد المنصة/الإصدار الذي  يستهدفه. كما للاستفادة من بعض خصائص الرسوميات الثلاثية الأبعاد في الإصدار 3.5 يتوجب عليك إستخدام ويندوز فيستا.

8. مايكروسوفت تكره أن تراك تتعلم و تتقدم مستخدما تقنيات بديلة سواءا كنت شركة أو بلد، و ستقوم بكل الأساليب للضغط عليك بطريقة مباشرة أو غير مباشرة لتستخدم برمجياتها. ألم تسمع ببيع Windows و Office بثلاثة دولارات فقط! أتذكر من بينها صفقة الصين و صفقات مع بعض دول أروبا الشرقية و صفقة تزويد بلدان العالم الثالث بأجهزة حاسوب محمولة تعمل بنسخة ويندوز و أوفيس.

9. مايكروسوفت تحارب البرمجيات المقرصنة و في نفس الوقت تفضل أن تستخدم برمجياتها مقرصنة على أن تراك تستخدم لينوكس.

10. مايكروسوفت تحاول منع انتشار لينوكس و البرمجيات الحرة و المفتوحة المصدر بكل الطرق و الوسائل كالضغط على المصنعين و المزودين الأصلين OEMs. و يكفي القيام ببحث على غوغل مستخدما Leaked Microsoft Memo لترى نوايا مايكرسوفت الدفينة.

11. برمجيات مايكروسوفت من أسوء البرمجيات من حيث مشاكل الأمن و الثبات. ليس لهذا أي ارتباط بانتشار نظام ويندوز لأن أكثر الأنظمة تعرضا لمحاولات الاختراق هي لينوكس و بيسدي BSDs لأنهم يشكلون أكثر من 70% من الخوادم على الأنترنت و هم بذلك معرضون بشكل دوري لكل أشكال المخاطر. و يبقى السبب الرئيسي لمشاكل الأمان و الثبات على ويندوز هي الطريقة التي صمم بها هذا النظام.

المزيد بخصوص مايكروسوفت هنا، هنا و هنا.


هل ليس لنا بديل؟ بلى.
هل يمكن أن نقول لا؟ نعم.
هل يمكن أن تحدث الفرق؟ بالتأكيد.

قم بدعم و إستخدام البرمجيات الحرة و المفتوحة المصدر، شجع أصدقائك و مدرستك على إستخدامها و الإنتقال إليها كبديل، شجع على ثقافة المشاركة و القضاء على القرصنة من خلال البرمجيات المفتوحة و المحتوى المفتوح. إصنع حريتك بيدك.

لا نريد القضاء على مايكروسوفت و لكن نطلب منافسة شريفة، و التركيز على تحسين جودة البرمجيات بدلا من كل تلك التلاعبات.

يونيو 04، 2009

الحصيلة التقنية: 06/2009 - أ

انتهيت من تعلم أساسيات لغة البرمجة بايثون (Python). هذه اللغة رائعة لدرجة أنني أحيانا أحلم أنني أبرمج بها و أنا نائم :) . و لم أستعن بأي كتاب بل فضلت أن أقرأ بعض الدروس المختصرة و التطبيقية لبايثون، و هذا هو نفس النهج الذي اتبعه الصديق أحمد يوسف في كتابة كتاب بايثون. و قد صدر تحديث لهذا الكتاب قبل أيام و قمت بتحميله و قرأت الفصول الأربعة الأولى و سأنهيه في الأيام المقبلة، و لهذا فأنا أنصح بهذا الكتاب. كما قضيت و قتا لا بأس به محاولا إيجاد حلول لمشاكل المشروع Euler Project الذي يسعى إلى تحفيز المبرمجين على إيجاد حلول لمشاكل حسابية و برمجية باعتماد لغة برمجتك المفضلة.

كما قضيت الفترة السابقة محاولا التخلص من بعض الأعمال التي تقع تحت تصنيف ضفادع لا مفر من أكلها. و ما يزال بعضها ينتظر الأكل قبل نهاية هذا الشهر.

بالنسبة للخدمة التويتر Twitter أجد أنني بدأت الاستفادة منها بشكل إيجابي و مفيد و كمصدر أخر من مصادر المعرفة. إنها خدمة رائعة للتعرف على أفكار و اهتمامات الغير بشكل سريع و قريب. أتابع حاليا مجموعة من الأشخاص و المؤسسات التي تهتم بالعلوم و البيئة و أحاول تفادي كل مصادر التوترة المبالغ فيها أو تلك التي تصنف "كبيض مقلي" مثل "يوم كباقي الأيام"، "أحس بملل اليوم" إلخ..
بالنسبة لفيس بوك Facebook، لم أجد بعد أشخاص يتبادلون فيه المعلومات و المعارف بالشكل الذي أريد و يفضل الأغلبية أستخدامه كوسيلة تواصل و تعارف. لكن و رغم ذلك يعجبني و أحاول أن أشارك فيه بكل المعلومات العلمية التي أجدها قيمة أو مثيرة.

جديد التقنية هو:
  • إصدار الحزمة المكتبية KOffice 2.0: جربتها بشكل سريع، و هي ليست ببديل لأوبن أوفيس OpenOffice.org أو أوفيس بعد، كما لم يدعي أحدا ذلك :). و هي ستمر بسلسلة من الإصدارات في كل مرة يتم تحسينها، تماما كنفس السلسلة التي اتبعها فريق كيدي KDE 4.
  • برنامج التصميمات و الرسوميات الثلاثية الأبعاد Blender 2.49 الذي حسب ما ذكر في صفحة الإصدار أنه يضم تغيرات جد مهمة. لم أجربه بعد كما أن خبرتي فيه جد محدودة و أنا عازم على تعلم بعض الأساسيات في فصل الصيف. مثل هذه البرامج ممتعة و مفيدة لتقوية التصورات الفضائية.

بخصوص جوجل Google، قمت بتجربة الإصدار الثاني للمتصفح كروم Chrome 2.0 و قد أعجبتني سرعته، كما أن بساطته تجعل منه بديل لمستخدمي إنترنت إكسبلورر IE الذين يخشون التعقيد أو الصعوبة. كما شاهدت عرض Google Wave و هي أشبه بمنصة ستسمح للتواصل و تعاون و المشاركة بشكل تفاعلي أكبر و آني. هذا المشروع جد مثير و واعد، و أتوقع أن يتم استخدامه بشكل كبير في الشركات الصغيرة و المتوسطة لأنه سوفر لهم منصة واحدة توفر أغلب وسائل التواصل الإلكتروني في مكان واحد. سيكون مشروع Google Wave مفتوح المصدر بجزئه الأكبر و يترقب إصدار تجريبي له في أواخر هذه السنة.

أقوم حاليا بتعلم دروبال Drupal بعد أن تعلمت أساسيات جوملة Joomla و وورد بريس Wordpress. و أعتقد أن دروبال أكثر مرونة و تحكم و سيستقر اختياري عليه في أغلب الأعمال.

جيد، ماذا بعد؟ بعد إكتسابي لأساسيات البرمجة ببايثون سأشرع في المرحلة الثانية من تعلمي لبايكيوت PyQt4.

و رغم كل ما أقوم به فأنا غير راضي عن تقدمي و في أغلب الأحيان أرى نقسي أتقدم كتقدم الحلزون، لكن المهم هو أن نتقدم ولو خطوة نحو الأمام :)