如何逐个元素地求和两个矩阵?

how to sum two matrices element by element?

我是汇编新手,如果您能用汇编语言 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

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

(要遍历它,您当然可以执行 row_offset += width;这就是 2x3 字节矩阵代码中的 add ebx, 3。)

Per-element矩阵相加根本不用关心它们的维数,和per-element数组相加完全一样的问题。所以只需在每个数组上循环一个索引或指针并添加。

然后你不需要为行和列设置 2 个单独的索引,这只会让你的代码更复杂,或者(对于这么小的尺寸)几乎值得像你第二次那样完全展开。

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


这不是特别的:

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

这样声明,用 2 个单独的 db 行表示单独的行,相当于一个长数组。对于 MASM,它可能会更改 SIZEOF A(您可能只会得到与 A 标签实际上位于同一行的第一行),但其他任何内容都不会更改。

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

如果你愿意,你可以完全展开一个循环并进行一系列复杂的整数寄存器移动和添加操作,但这没有意义。


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

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

如果列数是 2 的 assemble-time-constant 次方(特别是 1、2、4 或 8;x86 寻址模式具有 2 位移位计数),则可以使用 A[ebx*4 + esi] 之类的东西对于索引)。

通常在 asm 语法中,您编写 [base + index*scale],但 Intel-syntax 汇编程序实际上并不关心寻址模式的组件出现在哪个顺序中。因此,如果您想在 C 中思考,其中左边的索引跨过整行到 select 一列,如果你有一个 uint8_t [2][4] 矩阵,那么把它写成 [A + ebx*4 + esi] 是有意义的,所以从一个元素到下一行的跨度是4.

对于双字元素(如您的第一个示例)而不是字节元素(如您的第二个示例),您需要将索引缩放或已经缩放 4(如 A[ebx*4] 或使它们的字节偏移量为使用 add esi, 4 而不是 inc esi.

如果你想通过在数组 C 上写入输出来总结任何 2 个数组 A 和 B,你可以提供如下 函数的输入参数矩阵 A 的大小等于矩阵 B 的大小,并且 矩阵 C 的:MAT_SIZE。 要计算 MAT_SIZE,您只需将行数乘以数字 列(单维和二维矩阵)。如果索引数 > 2 那么 MAT_SIZE 将是所有(最大索引 + 1)的乘积(假设 0 指向 第一个元素和 n-1 指向最后一个)。 我想矩阵包含 1 字节的单元格。

;Indexes Max-Index+1 MAT_Size 
;      3           8    8*8*8

;ROUTINE @@MAT

;INPUT: EAX: First matrix pointer. Unaltered
;       EDX: Second matrix pointer. Unaltered.
;       EBX: Target matrix pointer. Unaltered.
;       ECX: MAT_Size. Unaltered.

@@MAt:PUSH  EBP           ; Save EBP.
      MOV   EBP,EBX       ; Copy EBX into EBP.

      JECXZ @@00          ; If matrix is empty, terminate sub-routine.

      PUSH  ECX           ; Save ECX.

 @@01:Mov   BL,[EAX]      ; Load in BL first byte.
      Add   BL,[EDX]      ; Add to BL second byte.
      MOV   [EBP],BL      ; Save result in [EBP].

      INC   EAX           ; Increase First matrix pointer.
      INC   EDX           ; Increase Second matrix pointer.
      INC   EBP           ; Increase Target matrix pointer.

      LOOP  @@01          ; If target matrix is full, end.

      POP   ECX           ; Resume MAT_SIZE

      SUB   EAX,ECX       ; Adjust First matrix pointer.
      SUB   EDX,ECX       ; Adjust Second matrix pointer.

      MOV   EBX,EBP
      SUB   EBX,ECX       ; Adjust Target matrix pointer.

 @@00:POP   EBP           ; Resume EBP.

      RET                 ; Return from sub-routine.

在真正的 x86 模式下,假设矩阵在数据段中,您可以类似地写:

;Indexes Max-Index+1 MAT_Size 
;      3           8    8*8*8

;ROUTINE @@MT2

;INPUT: SI: First matrix offset. Unaltered
;       DI: Second matrix offset. Unaltered.
;       BX: Target matrix offset. Unaltered.
;       CX: MAT_Size. Unaltered.

@@MT2:PUSH  BP            ; Save BP.
      MOV   BP,BX         ; Copy BX into BP.

      JCXZ  @@00          ; If matrix is empty, terminate sub-routine.

      PUSH  CX            ; Save ECX.

 @@01:Mov   BL,DS:[SI]    ; Load in BL first byte.
      Add   BL,DS:[DI]    ; Add to BL second byte.
      MOV   DS:[BP],BL    ; Save result in [BP].

      INC   SI            ; Increase First matrix offset.
      INC   DI            ; Increase Second matrix offset.
      INC   BP            ; Increase Target matrix offset.

      LOOP  @@01          ; If target matrix is full, end.

      POP   CX            ; Resume MAT_SIZE

      SUB   SI,CX         ; Adjust First matrix offset.
      SUB   DI,CX         ; Adjust Second matrix offset.

      MOV   BX,BP
      SUB   BX,CX         ; Adjust Target matrix pointer.

 @@00:POP   BP            ; Resume BP.

      RET                 ; Return from sub-routine.