المصفوفات: مؤشران، عنوان واحد

المصفوفات: مؤشران، عنوان واحد

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

فهرسان، عنوان واحد

يُعطى موضع العنصر في المصفوفة بفهرسين: فهرس الصف، الذي يحدد الصف الذي ينتمي إليه، وفهرس العمود، الذي يحدد العمود الذي ينتمي إليه. يبدأ العد لكل منهما من 0، بالطريقة نفسها التي عملت بها الفهارس في درس المتجهات. تحتفظ الذاكرة بتسلسل مسطح واحد من الأرقام، لذا يجب أولًا دمج الفهرسين في فهرس مسطح واحد: اضرب فهرس الصف في عدد أعمدة المصفوفة، ثم أضف فهرس العمود. ومن هناك يصبح الفهرس المسطح عنوان بايت بالطريقة نفسها التي يصبح بها فهرس المتجه كذلك: address = base + index * 4.

تحويل صف وعمود إلى عنوان
mul t4, t1, t3 # t4 = فهرس الصف * عدد الأعمدة
add t4, t4, t2 # t4 = that + فهرس العمود (الفهرس المُسطَّح)
slli t4, t4, 2 # t4 = إزاحة البايت = الفهرس * 4
add t5, t0, t4 # t5 = عنوان العنصر في هذا الصف والعمود
lw t5, 0(t5) # t5 = القيمة عند ذلك العنوان

يضرب فهرس الصف في عدد الأعمدة. في درس المتجهات كان يمكن إجراء الضرب بإزاحة لأن 4 قوة للعدد اثنين، لكن عدد الأعمدة في المصفوفة عادة ليس كذلك، لذا يُستخدم هنا بدلًا من . يُضاف فهرس العمود، ثم تُضرب النتيجة في 4 باستخدام آخر (4 قوة للعدد اثنين، لذا لا تزال الإزاحة صالحة لهذا الجزء). وينتج عن ذلك إزاحة البايت للعنصر عند الصف والعمود المعطيين.

الفهرسة حسب الصفوف
index=0× 3 +0=0
1
0x10010000
2
0x10010004
3
0x10010008
4
0x1001000c
5
0x10010010
6
0x10010014
7
0x10010018
8
0x1001001c
9
0x10010020
01
0x10010000
12
0x10010004
23
0x10010008
34
0x1001000c
45
0x10010010
56
0x10010014
67
0x10010018
78
0x1001001c
89
0x10010020

الصف 0، العمود 0 يقابل الفهرس 0.

تُظهر الشبكة على اليسار كيف تُرسم المصفوفة على الورق. ويُظهر الصف الواحد على اليمين كيف تُرتَّب تلك الأرقام نفسها في الذاكرة. يتحرك التمييز عبر الشبكة بترتيب القراءة: الصف 0 من اليسار إلى اليمين، ثم الصف 1، ثم الصف 2. وفي اللحظة نفسها يضيء العنصر نفسه في الصف المسطح أدناه، لأن ضرب فهرس الصف في عدد الأعمدة وإضافة فهرس العمود يعطي عنوان ذلك العنصر، وهو ما يطابق القيمة السداسية عشرية المعروضة على الجانبين. لا يتعامل RISC-V إلا مع الصف المسطح على اليمين. الشبكة هي شكل يفرضه تخطيط .data في برنامجك وقراءتك الخاصة له على تلك السلسلة الواحدة، باستخدام حساب و و الموضح أعلاه. وبمجرد فهم الشبكة والصف المسطح كشيء واحد معروض مرتين، يغطي النمط نفسه أي شبكة بيانات: صفوف البكسلات في صورة، أو لوح لعبة، أو جدول بيانات. كل منها مصفوفة واحدة، يُوصل إليها بضربة ضرب إضافية واحدة.

جمع المصفوفة

اجمع كل عنصر من عناصر مصفوفة 3 في 3
.data
m: .word 1, 2, 3, 4, 5, 6, 7, 8, 9 # مصفوفة 3×3، مخزّنة صفًا تلو الآخر
.text
la t0, m # العنوان الأساسي
li t1, 3 # عدد الصفوف
li t2, 3 # عدد الأعمدة
li t3, 0 # فهرس الصف الحالي، يبدأ من 0
li s0, 0 # المجموع الجاري
row_loop:
beq t3, t1, row_done
li t4, 0 # فهرس العمود الحالي، يبدأ من 0
col_loop:
beq t4, t2, col_done
mul t5, t3, t2 # فهرس الصف * عدد الأعمدة
add t5, t5, t4 # + فهرس العمود = الفهرس المسطّح
slli t5, t5, 2 # إزاحة البايت = الفهرس * 4
add t6, t0, t5 # عنوان العنصر في هذا الصف والعمود
lw t6, 0(t6) # القيمة عند ذلك العنوان
add s0, s0, t6 # المجموع += العنصر
addi t4, t4, 1 # ينتقل إلى العمود التالي
j col_loop
col_done:
addi t3, t3, 1 # ينتقل إلى الصف التالي
j row_loop
row_done:
mv a0, s0 # يطبع المجموع: 1+2+...+9 = 45
li a7, 1
ecall
li a7, 10
ecall

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

ℹ
يخزّن ترتيب الصفوف أولاً جميع أرقام الصف الأول، ثم جميع أرقام الصف الثاني، ويستمر على هذا النمط. هذا عرف وليس قاعدة. تستخدم لغات أخرى، ومنها Fortran، ترتيب الأعمدة: جميع أرقام العمود الأول، ثم جميع أرقام العمود الثاني، وهكذا. يجب أن يتفق كاتب البيانات وقارئ البيانات على التخطيط المستخدم. تقرأ RISC-V وتكتب عند أي عنوان تحسبه.