首页 > 解决方案 > 如何逐个元素地对两个矩阵求和?

问题描述

我是汇编新手,如果您能帮助我编写一段关于如何添加两个矩阵并将结果移动到另一个矩阵中的代码,使用汇编语言 x86-32 位,我将不胜感激。矩阵被声明为一维数组。

n dd 9
A dd 1,2,3,4,5,6,7,8,9
B dd 2,0,4,5,6,7,0,1,3
sum dd dup 9(0)

我尝试了下面的代码,但它只适用于这样声明的矩阵,我需要一个用于声明为 1s 数组的矩阵。

A db 1,2,3
   db 4,5,6
B db 7,8,9
   db 10,11,12
.code
start:
mov eax , 0 
mov esi, 0 
mov ebx, 0 

add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al
mov al, 0
inc esi
add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al
mov al, 0
inc esi
add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al

mov al, 0
mov esi, 0
add ebx, 3 
add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al
mov al, 0
inc esi
add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al
mov al, 0
inc esi
add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al
 push 0
call exit
end start

标签: assemblymatrixx86addressing-mode

解决方案


内存中连续的矩阵(如 C 2D 数组)相当于 1D 数组,只是rows * cols内存中一行中的元素,无论您使用什么 asm 语法将它们放在那里。使它们成为二维矩阵的唯一因素是您如何索引它们,例如
flat_index row * width + col.

(并且为了循环它,你当然可以这样做row_offset += width;那是add ebx, 3你的 2x3 字节矩阵代码。)

矩阵的逐元素加法根本不必关心它们的维度,这与逐元素数组加法完全相同。所以只需在每个数组上循环一个索引或指针并添加。

然后,您不需要 2 个单独的行与列索引,这只会使您的代码更复杂,或者(对于如此小的尺寸)几乎值得像第二次那样完全展开。

(或者,如果您的 CPU 支持 SSE2,您可以使用 . 一次执行 4 个双字paddd。)


这并不特别:

A db 1,2,3
   db 4,5,6

像这样声明,db不同行有 2 行,相当于一个长数组。对于 MASM,它可能会更改SIZEOF A(您可能只会得到实际上与标签在同一行的第一行A),但没有其他任何更改。

随附的代码不适用于您的情况的原因是它使用字节元素,并且具有不同的矩阵大小(9 个元素而不是 6 个)。 与它的声明方式无关。

如果你愿意的话,你可以完全展开一个循环并做一堆复杂的移动和添加整数寄存器,但没有意义。


A[ebx][esi]在大多数(?)汇编程序中不是有效的语法。如果它组装,我认为它意味着
A[ebx + esi]。那将是写它的正常方式。

它没有为您进行矩阵索引,这就是为什么您仍然必须使用字节偏移量才能进入下一行。

A[ebx*4 + esi]如果列数是 2 的汇编时间常数幂(特别是 1、2、4 或 8;x86 寻址模式对索引有 2 位移位计数),您可以使用类似的东西。

通常在您编写的 asm 语法中[base + index*scale],但英特尔语法汇编器实际上并不关心寻址模式的组件出现的顺序。因此,如果您喜欢在 C 中思考,其中左索引跨越整行以选择一列,如果你有一个矩阵,那么写它是[A + ebx*4 + esi]有意义的uint8_t [2][4],所以从一个元素到下一行的步幅是 4。

对于 dword 元素(如您的第一个示例中)而不是字节元素(如您的第二个),您需要缩放您的索引或 4 已经(例如A[ebx*4]或通过使用add esi, 4而不是inc esi.


推荐阅读