Assembly 用汇编语言添加两个矩阵
我正在编写一个汇编程序,将两个3X6矩阵相加,然后将结果放入一个新矩阵。我遇到了一些问题 问题是矩阵1的输出仅为2-16,矩阵2的输出仅为20-34。我似乎想不出如何让它充分发挥作用Assembly 用汇编语言添加两个矩阵,assembly,nasm,Assembly,Nasm,我正在编写一个汇编程序,将两个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
%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
对于
cx={5,4,3,2,1}
,内部循环L2
将只执行5次。外部循环将通过bx={2,1,0}
(确定)。因此,总共只使用15个值。如果矩阵是3x6,那么行的大小也应该是6(同样也是NO\u列
,实际上为什么需要两个常数来覆盖相同的逻辑)
但总的来说,你只是朝着错误的方向前进。当需要特定矩阵元素(“随机”访问)时,需要进行索引计算
要将两个大小相同的矩阵相加,顺序访问就足够了,因为您需要处理所有元素
你甚至可以忘记矩阵有多少个维度,因为所有三个(源矩阵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
...
如您所见,我再次避免了元素计算的“随机访问”索引,以连续的方式再次访问它们,只需对下一个元素执行基本的add si,2
,没有缓慢的mul
甚至一些复杂的计算
这就是汇编代码编写速度快的原因,优化算法以避免执行无用的指令,如果通过执行offset=(y*ROW\u SIZE+x)*element\u SIZE
,继续计算每个元素的完整索引,那么最终的代码速度将比任何半体面的高级语言编写的好代码都慢(C、Java、C#……所有这些编译器都会将两个嵌套循环视为优化机会,并生成类似于我在asm中编写的代码,其中只有一个循环遍历连续的偏移量)
因此,在编写任何代码之前,您应该首先确保完全理解要计算的内容及其原因,并尽可能简化它以避免任何冗余操作
在您看到调试器中的单步执行指令之前,您将很难发现代码中的所有问题,正如您在最后4个问题中很好地演示的那样。我欣赏您的固执,但您看起来没有足够的天赋在没有调试器的情况下继续进行,最终获得一些,并学会使用再重复几次你以前的问题和别人的提示,看看这次你能重复多少并完全理解。感谢这些建议。我会听从你的建议。@Rubiks顺便说一句,你的指数计算代码基本上是正确的(输入
cx
是错误的,这就是为什么它没有覆盖所有元素的完整矩阵。。哦,行大小也是错误的)。冗余的,正如您从我的“添加”例程中看到的,该例程忽略了维度,只需遍历从索引0到最后一个索引(=M*N-1)的所有元素,完全忽略二维坐标,但正确,因此您的问题是坐标错误(在调试过程中可以看到)。因此,您成功地编写了代码中更复杂的部分,正确地计算索引,并在更简单的循环部分卡住了…:)我还有一个问题。如果我想旋转矩阵1,最好的方法是什么?Rubiks:旋转?转置还是旋转?如果矩阵足够大,保持它们的原样并只收集变换信息可能会更便宜(您可以将旋转/转置/翻转平移组合成一个复杂的信息,如涉及变换矩阵相乘时的3D,但此处的变换信息类似于2x2矩阵、起始角和行/列方向)然后,矩阵的最终添加将使用较慢的索引计算,包括坐标的最终转换。对于较小的矩阵,转换数据可能更便宜。在您的情况下,我将坚持按字面方式转换数据,因此您将获得具有旋转值的矩阵的新副本。索引计算将是不像在我的代码(+2,+2)中那样简单,您必须在两个嵌套循环中计算2个维度,但是如果您检查元素的索引是如何演变的,您很可能能够避免使用mul
进行完整的索引计算,只需对起始索引值进行add/sub
调整(比如在原始矩阵上+2,以及目标索引的Z字形更新)。使用钢笔+纸张的例子来了解你需要什么,寻找模式。