用汇编添加两个矩阵

adding two matrices with assembly

我正在编写一个汇编程序,它将采用两个 3X6 矩阵,将它们相加,然后将结果放入一个新矩阵中。我 运行 遇到了一些问题。

问题是它只为矩阵 1 输出 2-16,为矩阵 2 输出 20-34。我似乎无法弄清楚如何让它使用整个范围。

%include "io.mac"
.STACK 100H 
.DATA
 NO_ROWS EQU 3
 NO_COLUMNS EQU 5
 SIZE_OF_ROW EQU 5
 SIZE_OF_ENTRY EQU 2


 matrix1 
 dw 1,2,3,4,5,6
 dw 7,8,9,10,11,12
 dw 13,14,15,16,17,18

 matrix2 
 dw 19,20,21,22,23,24
 dw 25,26,27,28,29,30
 dw 31,32,33,34,35,36

matrix3 TIMES 40 DW 0
 .CODE
 .STARTUP


mov  CX, NO_ROWS ; set outer loop count

L1: ; begin the outer loop   
    push CX ; save outer loop count
    mov BX, CX ;move outer loop count into EAX
    sub bx, 1
    mov CX, 5 ; set inner loop count

L2:
   ; use formula arrayName + (elements_in_a_row*row_number + element) *size_of_entry
mov si, 0
mov di, 0
mov dx, 0
mov si, matrix1
mov di, matrix2
mov ax, SIZE_OF_ROW
mul bx ;multiply ax by which row you're on.
add ax, cx ;then add column count, for which column you're on.
shl ax, 1 ;then multiply it by the size of each entry.
add si, ax ; so that the index points to the element.
add di, ax
mov ax, [si]
add ax, [di]
mov [matrix3], ax
PutInt [matrix3]
nwln
add word [matrix3], 2



    loop L2 ; repeat inner loop
    pop CX ;restore outer loop
    loop L1 ;repeat outer loop




 done:
 .EXIT

内部循环 L2 将只为 cx={5, 4, 3, 2, 1} 执行 5 次。外循环将通过 bx={2, 1, 0} (ok)。因此总共只使用 15 个值。另外 SIZE_OF_ROW 应该是 6,如果矩阵是 3x6(也是 NO_COLUMNS 实际上为什么你需要两个常量覆盖相同的逻辑)。

但总的来说,你只是走错了方向。当您需要特定的矩阵元素("random" 访问)时,需要进行索引计算。

要将两个相同大小的矩阵相加,顺序访问就足够了,因为您需要处理所有元素。

你甚至可以忘记矩阵有多少维度,因为所有三个(源矩阵 A 和 B,以及结果矩阵 C)都具有相同的大小 => 它们具有相同的总元素数。

在你的例子中,矩阵是 3x6 = 18 个元素。每个元素的大小为 word(2 个字节)。所以每个矩阵将占用 36 个字节(或 18 个字)。您以连续的方式定义了它们(下一行在上一个 = 好的设计结束后立即开始)。

这样的过程将进行矩阵加法:对于相同大小的矩阵,C = A + B:

; Same-size matrices addition (of 16b word elements): C = A + B
; ds:si = A address, ds:bx = B address
; ds:di = C address, cx = total amount of elements
; modifies: all input registers and ax
matrices_add:
    mov    ax,[si]
    add    ax,[bx]     ; ax = A[i] + B[i]
    mov    [di],ax     ; C[i] = ax
    ; ++i (actually advancing all three pointers instead of using index)
    add    si,2
    add    bx,2
    add    di,2
    ; loop until all elements are added
    dec    cx
    jnz    matrices_add
    ret

现在在你的情况下你可以用这些参数调用它:

NO_ROWS     EQU 3
NO_COLUMNS  EQU 6      ; fixed

    ...
    mov    si,matrix1
    mov    bx,matrix2
    mov    di,matrix3
    mov    cx,(NO_ROWS*NO_COLUMNS)
    call   matrices_add
    ; here memory at address matrix3 will contain matrix1+matrix2 elements
    ...

停止使用控制台输出进行调试,并从 MS 获取一些 DOS 调试器,如 Turbo Debugger 或 CV.EXE(代码视图)。或者使用内置调试器的虚拟机 BOCHS,这是更强大的解决方案,甚至可以在 DOS 运行.

之前调试引导程序。

如果你想显示矩阵,而不是使用单独的代码,以避免在加法过程中产生一些不必要的影响并使调试更容易(例如你可以先尝试显示 matrix1 然后退出回到 DOS,只是为了验证输出例程是否正确:

    ...
    mov    si,matrix3      ; pointer to next element
    ; output 3x6 16b matrix from "si" address
    mov    dx,NO_ROWS
output_matrix_row:
    mov    cx,NO_COLUMNS
output_matrix_line:
    PutInt [si]            ; display next element
    PutCh  ' '             ; make space between elements
    add    si,2            ; adjust pointer to point to next element
    dec    cx
    jnz    output_matrix_line
    nwln                   ; new line
    dec    dx
    jnz    output_matrix_row
    ...

如你所见,我再次避免了元素计算的 "random-access" 索引,以连续的方式再次访问它们,只需为下一个元素做基本的 add si,2,不慢 mul 甚至一些复杂的计算。

这就是用汇编编写的代码速度快的原因,您可以优化算法以不执行无用的指令,如果您将通过执行 offset = (y*ROW_SIZE + x)*ELEMENT_SIZE 继续计算每个元素的完整索引,您将以较慢的代码结束比用任何半正经的高级语言(C、Java、C# ...循环遍历连续的偏移量)。

所以在编写任何代码之前,您应该首先确保您完全了解您要计算的内容和原因,并尽可能简化它以避免任何冗余操作。


除非您在调试器中看到单步执行单指令,否则您将很难捕捉到代码的所有问题,正如您在最后 ~4 个问题中很好地演示的那样。我很欣赏你的固执,但你看起来没有足够的天赋在没有调试器的情况下继续进行下去,最终得到一些,并学会使用它并多次检查你的旧问题+其他人的提示,看看你会做多少这次能够复制+完全理解。