القيام بالرياضيات

القيام بالرياضيات

تحدث جميع العمليات الحسابية بين السجلات. تسمّي تعليمة حسابية الوجهة أولاً، ثم يتبعها المصدران اللذان تقرأهما: تعني dest = src1 + src2.

عملية حسابية
t2, t0, t1←add
t0 = 7t1 = 5+t2 = 12

أضف الموضعين t0 و t1 إلى t2.

الخطان الداخلان من اليسار هما t0 وt1، دائمًا بهذا الترتيب. يدخلان بالشكل نفسه بغض النظر عن العملية الجارية: جمع، طرح، ضرب، قسمة، أو باقٍ. تدخل قيمتان، وتحدث عملية واحدة، وتخرج نتيجة واحدة إلى t2 على اليمين. يسمّي الـ t2 أولاً لأن النتيجة تحلّ هناك، وهذا يطابق قاعدة الترتيب الوحيدة التي تتبعها كل تعليمة حسابية في هذا الدرس.

الجمع والطرح

يأخذ الرقمين المحفوظين في سجلين ويخزّن مجموعهما في سجل ثالث. يفعل الشيء نفسه للطرح: يحسب t0 - t1. تقرأ كلتا التعلميتين من السجلات فقط.

تسجيل الحساب
add t2, t0, t1 # t2 = t0 + t1
sub t2, t0, t1 # t2 = t0 - t1

شيء يجب معرفته: يحمل السجل 32 بت فقط، لذا هناك سقف. إذا كانت النتيجة أكبر من أن تتسع، فلا يُرفع أي خطأ. تلتفّ القيمة بهدوء وتعود إلى أرقام منخفضة جدًا ويستمر التنفيذ. لن تصل القيم اليومية إلى هذا الحد، لكن السقف يستحق المعرفة.

لاستخدام رقم ثابت بدلاً من سجل ثانٍ، أضف الحرف i الذي يرمز إلى القيمة الفورية: يضيف الثابت 1. لا يوجد subi، لذا لطرح ثابت تضيف قيمة سالبة: .

💡
يضيف ثابتًا. ويضيف سجلين. الخلط بينهما هو الخطأ الأكثر شيوعًا لدى المبتدئين.

الضرب والقسمة

يضرب سجلين. يقسمهما كأعداد صحيحة ويتجاهل الكسر، لذا 7 / 2 يعطي 3. يعطي الباقي، لذا 7 % 2 يعطي 1. لا تسبب القسمة أي انهيار أبدًا. القسمة على صفر تُرجع -1.

الضرب، القسمة، الباقي
mul t2, t0, t1 # t2 = t0 * t1
div t2, t0, t1 # t2 = t0 / t1 (عدد صحيح)
rem t2, t0, t1 # t2 = t0 % t1 (الباقي)

تجميع العناصر

اجمع رقمين واطبع النتيجة
li t0, 7
li t1, 5
add t1, t0, t1 # t1 = 7 + 5 = 12
mv a0, t1 # خدمة الطباعة تقرأ a0
li a7, 1
ecall
li a7, 10
ecall

يحمّل 7 في t0. يحمّل 5 في t1. يجمعهما ويكتب 12 في t1. ينسخ النتيجة إلى a0، لأن خدمة print تقرأ قيمتها دائمًا من a0. ثم يختار خدمة print-integer و يشغّلها. أخيرًا، و ينهيان البرنامج.

مكافأة: الضرب باستخدام عمليات الإزاحة

عندما يكون العامل قوة للعدد اثنين، توجد طريقة أسرع من . ينقل (الإزاحة المنطقية لليسار) بتات السجل إلى اليسار، وكل موضع تزيحه يضاعف القيمة: أزح بمقدار 1 للضرب في 2، وبمقدار 2 للضرب في 4، وبمقدار 3 للضرب في 8. تكلفة الإزاحة أقل من الضرب، لذا يستخدمها المترجمون كثيرًا.

الضرب في 8 باستخدام عمليات الإزاحة
li t0, 5 # ابدأ بـ 5
# إزاحة لليسار بمقدار 3 بتات (5 * 2^3 = 5 * 8)
sll a0, t0, 3 # a0 = 40
li a7, 1 # طباعة عدد صحيح
ecall
li a7, 10
ecall

يضع 5 في t0. يزيح بتاته ثلاثة مواضع إلى اليسار. كل موضع يضاعف القيمة، لذا تتضاعف 5 ثلاث مرات (5، 10، 20، 40)، مما يعطي 40 في a0. والباقي يتبع نمط print السابق. جرّب تغيير 3 إلى 1 أو 2 وتوقّع النتيجة قبل تشغيله.

الضرب بالإزاحة
5sll a0, t0, 0
×2 →
10sll a0, t0, 1
×2 →
20sll a0, t0, 2
×2 →
40sll a0, t0, 3
0
0
0
0
0
1
0
1

5 تم تحريكه لليسار 0 بت يبقى 5.

المربعات الثمانية هي الشكل الثنائي للرقم فوقها، بت واحد لكل منها، تُقرأ من اليسار إلى اليمين كالمعتاد. إزاحة الصف كله موضعًا واحدًا إلى اليسار هي العملية نفسها كالضرب في 2، لأن نقل رقم موضعًا واحدًا إلى اليسار في أي أساس يضرب قيمته في ذلك الأساس. الأساس الثنائي له رقمان فقط، لذا فإن المضاعف هو 2. إزاحة ثلاث مرات تجمع هذا إلى ضرب في 8، وهو ما يطابق ما يفعله بالرقم 5.