الشبكة العربية لمطوري الألعاب

محترف مشرف عبد اللطيف حاجي علي مشاركة 1

حسناً. بما أنه يبدو أنه لا أحد قرأ مقالتي عن الأرقام في الحاسوب (http://www.agdn-online.com/papers/ahali_numbers.zip) قررت أن أصدع رأسكم بالأسئلة الواردة في المقالة حتى أضمن الفائدة للجميع (قارئين و غير قارئين)
أتمنى أن تشاركوا بالأجوبة. وإن استعصى عليكم شيء فيمكنكم دوماً قراءة المقالة لأخذ فكرة الحل ولا تتردوا بالسؤال والمناقشة. في النهاية سأضع الحل الذي فكرت به لنناقشه.


حسناً إذا مع السؤال الأول:
اكتب برنامجاً (أو خوارزمية) لتحويل الأرقام الصحيحة الموجبة من أي نظام عد إلى آخر (تلميح: العدد 1059 يحوي على 9 من الآحاد (10^0) و 5 من العشرات (10^1) و 0 من المئات (10^2) و 1 من الآلاف (10^3) وصفر من بقية الفئات).

إذا هل من أجوبة؟

عبد اللطيف حاجي علي
مبرمج
In|Framez

محترف  انس مشاركة 2

السلام عليكم 😄 .
اليك محاولتي استاذ عبد اللطيف،مجرد خوارزم تحويل عدد طبيعي الى النظام الثنائي.
#include 
#include 
#include 

int Dicimal_to_binair ( int number ) {

    int  rest = 0 ;
    int  bin_form =0;
    int  i = 0;

    while( number != 0 ) {


       rest = number%2;
       number/=2;

       if( rest != 0 ) bin_form += ceil( pow(10,i) );
       i++     ;


        }

    return bin_form ;
    }

int main()
{


int user_num = 0 ;

printf("please insert a number : \n");
scanf("%d",&user_num);
printf("The Binairi form of your number is : %d \n",Dicimal_to_binair ( user_num ) );

    return 0;
}

انا في طريق وضع الخوارزم اللازم للاجابة الكافية عن سؤالك لكنني اجد بعض الصعوبات،لهذا وضعت هذا الكود حتى ارى ان كانت المبادئ التب عملت عليها صحيحة .

حسنا الشرح :

اعتمدت على طريقة القسمة للتحويل الى النظام الثنائي،اذ انه اذا قسمنا اي عدد على اثنان فسوف تظهر خالتان فقط و هي اما الباقي 0 ام 1
نحتفظ بهذه القيمة ثم نقوم بنفس الشيئ ما دام العدد المراد تحويله مختلف عن 0 .

في النهاية الاعداد الناتجة من الباقي و العدد الناتج الاخير ( دائما 1 )، ة التي تقرء بشكل معكوس اي من العملية n الى العملية 0 . هده السلسلة من ال 0 و 1 هي الترميز الخاص بالعدد من النظام العشري الى النظام الثنائي.

هل هذا مقبول ؟ام انني ....احححمم ☺

شكرا على التمرين .

بنفس المبدا كتبت برنامجا لتحويل الارقام من النظام العشري الى الثماني هاهو الكود :



int Dicimal_to_octal ( int number ) {

    int rest = 0 ;
    int  oct_form =0;
    int i = 0;

    while( number != 0 ) {


       rest = number%8;
       number/=8;

       oct_form += rest*ceil( pow(10,i) );
       i++     ;


        }

    return oct_form ;
    }



سلام

محترف مشرف عبد اللطيف حاجي علي مشاركة 3

أحسنت أخي أنس ☺ . حلّك يحوي على المبادئ الأساسية الصحيحة اللازمة للحل المثالي.

لكن هناك تفصيل برمجي أو اثنين يجب أن أنوّه لهم:

1. الإجراء الذي كتبته يأخذ ويعيد قيمة من نوع int وهو محدود نوعاً ما. فمثلأً لا يمكن تمثيل الأعداد الكبيرة نسبياً في نظام العد الثنائي باستخدام هذا النوع (كمثال حاول تحويل القيمة 1500 باستخدام برنامجك. هل تستطيع تعليل لماذا لا نستطيع تمثيل هذا العدد ثنائياً باستخدام النوع int مع أن حجمه 32 بت؟) كما أن تطوير هذا البرنامج لتحويل بقية الأسس أمر شبه مستحيل باستخدام هذا النوع.
أقترح أن تستخدم مصفوفة من المحارف (character array) أو إذا كان لديك المعرفة الكافية بالـ C++ فاستخدم std::string بحيث يدخل المستخدم سلسلة من المحارف و تقوم بتحويلها إلى سلسة أخرى من المحارف (أتمنى أن تكون هذه النقطة واضحة)

2. حاول الابتعاد قدر الإمكان عن استخدام إجراءات رياضية معقدة وبطيئة مثل pow أو ceil. هذا لا يؤثر طبعاً على الحل من الناحية الرياضية أو الوظيفية بل يؤثر عليه من ناحية سرعة الأداء.

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

عبد اللطيف حاجي علي
مبرمج
In|Framez

محترف  انس مشاركة 4

السلام عليكم استاذ عبد اللطيف،شكرا على التوضيحات ساحاول ان اجيب على اسئلتك 😄 .

وفي 25 اغسطس 2009 05:38 م، ظهر شبح ابتسامة على وجه عبد اللطيف حاجي علي وهو يقول:

1. الإجراء الذي كتبته يأخذ ويعيد قيمة من نوع int وهو محدود نوعاً ما. فمثلأً لا يمكن تمثيل الأعداد الكبيرة نسبياً في نظام العد الثنائي باستخدام هذا النوع (كمثال حاول تحويل القيمة 1500 باستخدام برنامجك. هل تستطيع تعليل لماذا لا نستطيع تمثيل هذا العدد ثنائياً باستخدام النوع int مع أن حجمه 32 بت؟) كما أن تطوير هذا البرنامج لتحويل بقية الأسس أمر شبه مستحيل باستخدام هذا النوع.

نعم اعلم ان الاجراء الذي كتبته محدود جدا،ختى انه لا يتعامل الا مع الاعداد الطبيعية الموجبة فقط.

بالنسبة للعدد 1500 فانه -اي 1500 و ليس رمزه في النظام الثنائي- لا يشكل مشكلة مع الـ int
المشكلة هي اننا عندما نفوم بتحويل 1023 نتحصل على 1111111111 كل ئيئ على مايرام لحد الان، لكن اذا تجاوزنا هذه القيمة فهنا سنخرج من نطاق قيم الـ int و المحددة ضمن المجال

-2 147 483 648 to 2 147 483 647

لان 1024 يعطي  10000000000 .
كنت اظن ان الامر يمكن معالجته بشكل محدود  باستعمال الكلمة المفتاحية  unsigned لكن النتيجة غريبة او ان مفهومي خاطئ ، يرجى التوضيح استاذ 😄 .

النوع الامثل هو Double  و ذلك لحجمه الضخم .



أما في 25 اغسطس 2009 05:38 م، فقد تنهد عبد اللطيف حاجي علي بارتياح وهو يرد:

أقترح أن تستخدم مصفوفة من المحارف (character array) أو إذا كان لديك المعرفة الكافية بالـ C++ فاستخدم std::string بحيث يدخل المستخدم سلسلة من المحارف و تقوم بتحويلها إلى سلسة أخرى من المحارف (أتمنى أن تكون هذه النقطة واضحة)
هذه الطريقة خمت فيها عندما اردت التحويل الى النظام السداسي عشر لاضافة الحروف الابجدية.ساحاول تعميمها.لكن ما افكر فيه قد يكون مكلفا.😠

في 25 اغسطس 2009 05:38 م، غمغم عبد اللطيف حاجي علي باستغراب قائلاً:

2. حاول الابتعاد قدر الإمكان عن استخدام إجراءات رياضية معقدة وبطيئة مثل pow أو ceil. هذا لا يؤثر طبعاً على الحل من الناحية الرياضية أو الوظيفية بل يؤثر عليه من ناحية سرعة الأداء.

حسنا هل تصدق انني لاول مرة استعمل هاتين الدالتين ؟ خصوصا الدالة Ceil استعملتها لان البرنامج كان يعطي نتيجة غريبة جدا عند pow(10,2)q
كان يعطي 99 😒 لهدا لجات اليها.

مشكلاتي الان في كتابة الاجراء الذي ياخذ اي عدد ينتمي الى اي نظام و يحوله الى النظام العشري. بعد شد و مد فهمت المبدا لكنني الان افكر في كيفية استخلاص الاعداد المختلفة لتطبيق القاعدة.

مثال :
                6 5 4 3 2 1 0
Binair Number : 1 1 0 1 1 0 0 
القاعدة تقول :

N = some(Ai*B^i)
المشكلة هي تخزين رقم كل خانة و العدد الذي تحتويه.

هناك شيئ اخر اود ان تشرحه لي، طريقة القسمة ليست الطريقة الوحيدة للتحويل الى النظام الثنائي هناك طريقة تعمل بمبدا الطرح لم استوععبها فهل يمكنك شرحها من فضلك ؟

شكرا جزيلا مرة اخرى

سلام

محترف مشرف عبد اللطيف حاجي علي مشاركة 5

في 26 آب 2009 12:15 ص، غمغم انس باستغراب قائلاً:

لان 1024 يعطي  10000000000 .

نعم المشكلة أن طريقتك في الترميز لا تستفيد من كافة القيم التي يمكن للنوع int أن يمثلها. بل تقتصر على القيم التي تتألف من الرمزين 1 و 0 في الترميز العشري (أي هناك ملايين القيم الأخرى التي تحوي على رموز أخرى 2، 3... 9).

بتاريخ 26 آب 2009 12:15 ص، قطب انس حاجبيه بشدة وهو يقول:

كنت اظن ان الامر يمكن معالجته بشكل محدود  باستعمال الكلمة المفتاحية  unsigned لكن النتيجة غريب

لا شيء غريب هنا. باستخدام int يمكنك ترميز حتى 2,147,483,647 أي عشر منازل. وباستخدام unsigned int فإن الرقم السابق يتضاعف لكنه يبقى مؤلفاً من عشر منازل. وبالتالي لا يمكنك ترميز الأعداد التي تحوي على أكثر من 10 بتات باستخدام طريقتك



وفي 26 آب 2009 12:15 ص، أعرب انس عن رأيه بالموقف كالآتي:

النوع الامثل هو Double  و ذلك لحجمه الضخم .

حتى لو استخدمت النوع long long long double والذي يتألف من 128 بت (إن كان يوجد هكذا نوع) فإن المشكة تبقى قائمة. الأعداد التي يمكنك ترميزها محدودة. الحل الأمثل هو استخدام مصفوفة محارف. كما أن استخدام مصفوفة محارف سيساعدك على فهم مبدأ الترميز أكثر من ترميز اعداد ثنائية على أنها عشرية.



في 26 آب 2009 12:15 ص، قال انس بهدوء وتؤدة:

خصوصا الدالة Ceil استعملتها لان البرنامج كان يعطي نتيجة غريبة جدا عند pow(10,2)qكان يعطي 99

هذه أحد الأخطاء الشائعة التي يقع فيها من يحول متغيراً من نوع float أو double إلى int. المشكلة تكمن في أن pow(10,2) لا يعيد العدد 100 بالضبط. بل يعيد عدداً قريباً جداً منه من شاكلة 99.99999999 بخطأ صغير جداً نسبياً. الآن عندما تحول إلى int فإنك عملياً تهمل جميع الأعداد بعد الفاصلة وتصبح
النتيجة 99!


في 26 آب 2009 12:15 ص، عقد انس حاجبيه بتفكير وقال:

القاعدة تقول :N = some(Ai*B^i)
أعتقد أن تقصد

N = sum(Ai^B^i)


هل قرأت مقالتي؟ لقد شرحت كل هذه الأمور بالتفصيل والأمثلة.



وفي 26 آب 2009 12:15 ص، قال انس متحمساً:

المشكلة هي تخزين رقم كل خانة و العدد الذي تحتويه.


ما المشكلة فيهما بالضبط؟


وفي 26 آب 2009 12:15 ص، ظهر شبح ابتسامة على وجه انس وهو يقول:

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

لاحظ أنه حتى القسمة يمكن استبدالها بإزاحة منطقية (انظر مقالتي لمزيد من المعلومات)

عبد اللطيف حاجي علي
مبرمج
In|Framez