【问题标题】:how to sum two matrices element by element?如何逐个元素地对两个矩阵求和?
【发布时间】:2019-05-11 08:23:24
【问题描述】:

我是汇编新手,如果您能帮助我编写一段代码,说明如何使用汇编语言 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

【问题讨论】:

    标签: assembly matrix x86 addressing-mode


    【解决方案1】:

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

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

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

    那么您不需要 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 的汇编时间常数幂(特别是 1、2、4 或 8;x86 寻址模式对索引有 2 位移位计数),您可以使用类似 A[ebx*4 + esi] 的东西.

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

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

    【讨论】:

      【解决方案2】:

      如果您想通过在数组 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.
      

      【讨论】:

      • 我认为这没有得到任何支持的原因是这里的真正问题是 是否 2D 矩阵在汇编中看起来与 1D 数组相同。但可以肯定的是,请投赞成票,即使这使用了慢速 loop 指令。在指针递增循环之后减去大小是恢复原始寄存器值的一种有趣方法。 (但是,如果不展开循环,使用索引寻址模式在所有 CPU 上的效率至少与 3 个单独的指针增量相比在大多数 CPU 上的效率更高。)不过,对于一些初学者来说,举一个具体的例子可能会有所帮助.
      • 非常感谢 Peter Cordes 先生!你是我最好的。祝你好运。
      • Ora devo dormire ancora un pò e chiudo per un pò l' account come mi hanno detto ianche i moderatori.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-06
      • 1970-01-01
      • 2014-05-18
      • 1970-01-01
      • 2020-10-14
      • 2016-08-13
      • 1970-01-01
      相关资源
      最近更新 更多