انتقل إلى المحتوى
Topos Uranos

ملخص

العدد الصحيح في البرنامج ليس عددًا صحيحًا من أعداد الرياضيات: إنه متتالية منتهية من البتات، ومع nn بتًا تتسع بالضبط 2n2^n قيمة مختلفة. يدرس هذا الدرس ذلك التمثيل وعواقبه. فيعلّم كتابة عدد صحيح في الأساس 2 وفي الأساس 16 والتحقق منها بمواصفتَي التنسيق {:b} و{:x}؛ ويعرض الأنواع الصحيحة في C++، وحجمها الذي يُقاس بـ sizeof، ومدى قيمها الذي يُستعلم عنه بـ std::numeric_limits؛ ويشرح كيف تُمثَّل الأعداد السالبة بالمتمِّم الثنائي ولماذا لا يكون المدى متناظرًا؛ ويميّز الأعداد الصحيحة ذات الإشارة من عديمة الإشارة، ويدرس ما يحدث حين تخرج عملية عن المدى: في عديمة الإشارة يعرّف المعيار النتيجة، وهي الحساب بترديد 2n2^n؛ وفي ذات الإشارة لا يعرّفها، فيخرج البرنامج عن كل ضمان. ويختم بمعيار لاختيار نوع كل معطى.

أهداف التعلم

  1. تحويل الأعداد الصحيحة بين الأسس 10 و2 و16، والتحقق من التحويل بمواصفتَي التنسيق {:b} و{:x}.
  2. حساب مدى قيم عدد صحيح من nn بتًا، ذي إشارة وعديم الإشارة، والتحقق منه بـ std::numeric_limits وsizeof.
  3. شرح المتمِّم الثنائي وكتابة تمثيل عدد سالب صغير في ثمانية بتات.
  4. التمييز بين الفيضان ذي الإشارة، وهو سلوك غير معرَّف، والفيضان عديم الإشارة، وهو حساب بترديد 2n2^n، والتنبؤ بنتيجة الثاني.
  5. اختيار النوع الصحيح المناسب لمعطى بحسب مداه المتوقَّع، باستعمال الأنواع ذات العرض الثابت من <cstdint> حين يكون العرض مهمًّا.

أنظمة العدّ الموضعية

قدّم درس المتغيرات والذاكرة المتغيرَ بوصفه خانة لها اسم ونوع وقيمة. غير أنّ الذاكرة لا تحفظ أرقامًا عشرية: إنها تحفظ بتات، كلٌّ منها قيمته 0 أو 1، مجمَّعة في بايتات من ثمانية بتات (يشترط المعيار ثمانية على الأقل؛ وكل الأنظمة الحالية تستعمل ثمانية بالضبط). فلمعرفة القيم التي يمكن أن يأخذها متغير صحيح لا بدّ إذن من معرفة كيف يُكتب عدد برقمين فقط، وهذا ما يفعله نظام العدّ الموضعي ذو الأساس 2.

في نظام العدّ الموضعي ذي الأساس bb، يساوي كل رقم بحسب الموضع الذي يشغله: الأخير يُضرب في b0=1b^0 = 1، والذي قبله في b1b^1، والذي قبل ذاك في b2b^2، وهكذا. في الأساس 10، يعني 20262026 العددَ 2⋅103+0⋅102+2⋅101+6⋅1002 \cdot 10^3 + 0 \cdot 10^2 + 2 \cdot 10^1 + 6 \cdot 10^0. وفي الأساس 2 الأرقام هي 0 و1، والأوزان هي قوى العدد 2: 1,2,4,8,16,32,64,128,…1, 2, 4, 8, 16, 32, 64, 128, \ldots ومن ذلك تلزم قاعدة الانتقال من الثنائي إلى العشري: تُجمع أوزان المواضع التي فيها 1.

مثالمن الثنائي إلى العشري

يقرأ الشكل نمط البتات الثمانية 00101101. فوق كل خانة وزنها؛ وتُضاء الآحاد واحدًا بعد واحد، من اليسار إلى اليمين، وتجمع القيمة أوزانها.

البرهان

  1. ثماني خانات، كلها مطفأة: القيمة 0. والأوزان، من اليمين إلى اليسار، هي 1,2,4,…,1281, 2, 4, \ldots, 128.

  2. أول واحد في الموضع ذي الوزن 32: القيمة المتجمعة 32.

  3. الذي يليه، في الموضع ذي الوزن 8: 32+8=4032 + 8 = 40.

  4. الذي يليه، في الموضع ذي الوزن 4: 40+4=4440 + 4 = 44.

  5. الأخير، في الموضع ذي الوزن 1: 44+1=4544 + 1 = 45. النمط 00101101 يمثّل العدد 45.

  6. إذا جُمِّعت البتات أربعةً أربعةً أعطت الأرقام الست عشرية: 0010 هو 2 و1101 هو 13، الذي يُكتب في الأساس 16 d. لذلك يُكتب 45 في الأساس 16 2d.

أما الطريق العكسي، من العشري إلى الثنائي، فيُقطع بـالقسمة المتتالية: يُقسم العدد على 2، ويُسجَّل الباقي (0 أو 1)، ويُكرَّر ذلك مع خارج القسمة حتى الوصول إلى 0؛ والبواقي، مقروءةً من الأخير إلى الأول، هي الأرقام الثنائية. للعدد 45: 45=2⋅22+145 = 2 \cdot 22 + 1، 22=2⋅11+022 = 2 \cdot 11 + 0، 11=2⋅5+111 = 2 \cdot 5 + 1، 5=2⋅2+15 = 2 \cdot 2 + 1، 2=2⋅1+02 = 2 \cdot 1 + 0، 1=2⋅0+11 = 2 \cdot 0 + 1؛ والبواقي، مقروءةً بالعكس، تعطي 101101، وهو مع صفرين على اليسار نمط الشكل. والسبب أنّ كل باقٍ هو رقم آحاد العدد الذي يُقسم، وكل خارج قسمة هو ذلك العدد مزاحًا موضعًا واحدًا إلى اليمين. والطريقة نفسها تصلح لأي أساس: للأساس 16 يُقسم على 16، والبواقي من 10 إلى 15 تُكتب بالحروف من a إلى f.

الأساس 16، أو النظام الست عشري، موجود للراحة: بما أنّ 16=2416 = 2^4، فكل رقم ست عشري يقابل أربعة بتات بالضبط، ويُكتب البايت برقمين. والعدد ذو 32 بتًا يشغل اثنين وثلاثين رقمًا في الثنائي، تُقرأ بصعوبة، وثمانية فقط في الست عشري، تُحوَّل إلى الثنائي دون حساب، رقمًا رقمًا. لذلك يقرأ المبرمجون الذاكرة بالست عشري. والأساس الرياضي لأنظمة العدّ الموضعية يُدرس في دورة الجبر والهندسة 1، في درس «أنظمة العدّ الموضعية».

تقبل C++ أعدادًا صحيحة مكتوبة مباشرة بهذه الأسس: القيمة الحرفية التي تبدأ بـ 0b تكون بالثنائي، والتي تبدأ بـ 0x بالست عشري. وداخل أي قيمة حرفية يمكن وضع فاصلة عليا فاصلًا للأرقام، يتجاهلها المترجم ويقدّرها القارئ: 0b0010'1101، 1'000'000. وفي المخرجات، تكتب مواصفة التنسيق {:b} العدد الصحيح بالثنائي، و{:x} بالست عشري بحروف صغيرة، و{:X} بحروف كبيرة؛ والعلامة # تضيف البادئة في أوله، والعرض المسبوق بصفر يملأ اليسار بأصفار.

مثالعدد واحد بثلاث كتابات
برنامج بلغة C++
#include <print>​int main(){    const int decimal{45};    const int binary{0b0010'1101};    const int hexadecimal{0x2d};    std::println("{} {} {}", decimal, binary, hexadecimal);    std::println("ثنائيًا: {:b}", decimal);    std::println("ثمانية بتات: {:08b}", decimal);    std::println("ست عشريًا: {:x} {:X} {:#x}", decimal, decimal, decimal);}
المخرجات
45 45 45ثنائيًا: 101101ثمانية بتات: 00101101ست عشريًا: 2d 2D 0x2d

تحفظ المتغيرات الثلاثة القيمة نفسها، مكتوبة بثلاثة أسس، ويُظهر ذلك السطر الأول من المخرجات: الأساس خاصية للكتابة، لا للعدد. والذاكرة تحفظ في الحالات الثلاث نمط البتات نفسه. والمواصفة {:b} تحذف الأصفار التي على اليسار؛ و{:08b} تكمل ثمانية أرقام.