8086 汇编语言程序求 16 位十六进制数数组中奇数和偶数的个数
8086 assembly language program to find number of odd and even numbers in an array of 16-bit hexadecimal numbers
为了判断十六进制数是否为偶数,程序会将数字除以2,余数应为零。如果不是,那么它是一个奇数。最初,我的计划是我有一个变量或寄存器,当十六进制被证明是偶数时,它会递增。然后我会减去偶数的数量。到五得到奇数的数量。但是由于我必须使用三个寄存器来保存被除数和除数 (AX & BX
),再加上另一个用于数组计数器 (CX
),所以我 运行 超出寄存器来保存值“偶数计数器”。
我修改了程序,使其仍然可以满足指令(见标题)。这一次,程序将显示字符 E
表示偶数,O
表示奇数。我现在的问题是程序最多只能识别第二个数组项,这意味着 SI
的值保持不变并且在第二个数组项之后不会递增。这使得程序的输出 EOOOO
而不是 EOOOE
.
我的问题是:
1.) 我如何从内存中增加 SI
的值并将其传递给 AX
进行划分
2.) 我最初的计划是否可行?如果是,我可以用什么寄存器来保存“偶数计数器”
代码如下:
.MODEL SMALL
READ MACRO MSG
MOV AH,0AH
LEA DX,MSG
INT 21H
ENDM
SET MACRO MSG
MOV AH,09H
LEA DX,MSG
INT 21H
ENDM
.DATA
CR EQU 0DH
LF EQU 0AH
ARR DW 100h,16Fh,191h,10Fh,120h
MSG1 DB CR,LF,"Array of 16 bit hexadecimals: 100h,16Fh,191h,10Fh,120h$"
MSG2 DB CR,LF,"E=EVEN O=ODD$"
NUMERALEVEN DB CR,LF,"E$"
NUMERALODD DB CR,LF,"O$"
COUNT EQU 5H
DATA ENDS
.CODE
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
SET MSG1
SET MSG2
MOV SI,OFFSET ARR
MOV CL,COUNT
MOV AX,[SI]
MOV DX,0000
CHECK:
MOV DX,0000
MOV BH,00
MOV BL,02H ;divide by 2
DIV BX
CMP DX,0 ;checks if there is a remainder by comparing the remainder to 0
JE EVEN
JNE ODD
EVEN:
SET NUMERALEVEN
MOV DX,00
DEC CL
MOV AX,[SI+1]
MOV [SI],AX
CMP CL,0
JNZ CHECK
ODD:
SET NUMERALODD
DEC CL
MOV AX,00
MOV AX,[SI+1]
MOV [SI],AX
CMP CL,0
JNZ CHECK
CODE ENDS
END START
This makes the output of the program EOOOO
instead of EOOOE
.
您似乎没有完全意识到代码中的以下指令实际上做了什么:
MOV AX,00
MOV AX,[SI+1]
MOV [SI],AX
第一条指令没有用,因为第二条指令会覆盖AX
的值。
因为您的数组由 16 位值组成并且 x86 CPU 使用字节寻址(像大多数但不是所有 CPU),第二个值将存储在地址 [SI+2]
,而不是 [SI+1]
.
通过读取 [SI+1]
,您读取了一些(无意义的)值,这些值可以根据数组中的前两个数字计算得出。
并使用最后一条指令覆盖数组中的第一个数字,这对我来说毫无意义。
您永远不会修改 SI
寄存器。如果不修改 SI
寄存器,您以后将永远不会读取数组中的值!
所以您的程序执行以下操作:
Initially, your array contains the values 100h,16Fh,...
You check the value 100h (if it is even or odd)
MOV AX,[SI+1] loads 6F01h into AX
MOV [SI],AX overwrites the first value in the array by 6F01h
You check the value 6F01h (if it is even or odd)
MOV AX,[SI+1] loads 6F6Fh into AX
MOV [SI],AX overwrites the first value in the array by 6F6Fh
You check the value 6F6Fh (if it is even or odd)
MOV AX,[SI+1] loads 6F6Fh into AX
MOV [SI],AX has no effect ...
... because the first element of the array is already 6F6Fh
MOV AX,[SI+1] loads 6F6Fh into AX
...
MOV AX,[SI+1] loads 6F6Fh into AX
...
MOV AX,[SI+1] loads 6F6Fh into AX
...
所以你的程序第一次检查 100h
是偶数还是奇数。这就是你想要的。
第二次检查 6F01h
是偶数还是奇数。第三次、第四次、第五次……第十次……第一百次,它检查 6F6Fh
是偶数还是奇数。这可能是您不想要的。
In order to determine if the hexadecimal no is even, the program would divide the number by 2 and the remainder should be equal to zero.
如果您使用十进制数(没有计算机)并想检查一个数是否可以被 10 整除 - 您是否也可以将该数除以 10 并查看余数?
没有。您会查看最后一位数字并检查它是否为零。
您可以在所有数字系统中执行此操作:
在三进制中,如果最后一位为零,则数字可以被 3 整除;在十六进制系统中,如果最后一位为零,则它可以被 16 整除。在二进制系统中,如果最后一位(= 位)为零,则它可以被二整除。
您可以使用 TEST
指令来检查某个位是零还是一:
指令TEST xxx, 1
检查值xxx
的最后一位是否为0,如果是,则设置零标志(否则清除零标志)。这意味着如果该位为零,JZ
指令(与 JE
相同)将跳转。如果那个位是 1,JNZ
(JNE
) 将跳转。
所以可以用指令TEST AX, 1
替换下面的代码:
MOV DX,0000
MOV BH,00
MOV BL,02
DIV BX
CMP DX,0
而且您甚至可以使用 TEST WORD [SI], 1
直接检查数组中数字中的位,因此您甚至不需要使用 MOV AX, [SI]
将值加载到 AX
注册.
为了判断十六进制数是否为偶数,程序会将数字除以2,余数应为零。如果不是,那么它是一个奇数。最初,我的计划是我有一个变量或寄存器,当十六进制被证明是偶数时,它会递增。然后我会减去偶数的数量。到五得到奇数的数量。但是由于我必须使用三个寄存器来保存被除数和除数 (AX & BX
),再加上另一个用于数组计数器 (CX
),所以我 运行 超出寄存器来保存值“偶数计数器”。
我修改了程序,使其仍然可以满足指令(见标题)。这一次,程序将显示字符 E
表示偶数,O
表示奇数。我现在的问题是程序最多只能识别第二个数组项,这意味着 SI
的值保持不变并且在第二个数组项之后不会递增。这使得程序的输出 EOOOO
而不是 EOOOE
.
我的问题是:
1.) 我如何从内存中增加 SI
的值并将其传递给 AX
进行划分
2.) 我最初的计划是否可行?如果是,我可以用什么寄存器来保存“偶数计数器”
代码如下:
.MODEL SMALL
READ MACRO MSG
MOV AH,0AH
LEA DX,MSG
INT 21H
ENDM
SET MACRO MSG
MOV AH,09H
LEA DX,MSG
INT 21H
ENDM
.DATA
CR EQU 0DH
LF EQU 0AH
ARR DW 100h,16Fh,191h,10Fh,120h
MSG1 DB CR,LF,"Array of 16 bit hexadecimals: 100h,16Fh,191h,10Fh,120h$"
MSG2 DB CR,LF,"E=EVEN O=ODD$"
NUMERALEVEN DB CR,LF,"E$"
NUMERALODD DB CR,LF,"O$"
COUNT EQU 5H
DATA ENDS
.CODE
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
SET MSG1
SET MSG2
MOV SI,OFFSET ARR
MOV CL,COUNT
MOV AX,[SI]
MOV DX,0000
CHECK:
MOV DX,0000
MOV BH,00
MOV BL,02H ;divide by 2
DIV BX
CMP DX,0 ;checks if there is a remainder by comparing the remainder to 0
JE EVEN
JNE ODD
EVEN:
SET NUMERALEVEN
MOV DX,00
DEC CL
MOV AX,[SI+1]
MOV [SI],AX
CMP CL,0
JNZ CHECK
ODD:
SET NUMERALODD
DEC CL
MOV AX,00
MOV AX,[SI+1]
MOV [SI],AX
CMP CL,0
JNZ CHECK
CODE ENDS
END START
This makes the output of the program
EOOOO
instead ofEOOOE
.
您似乎没有完全意识到代码中的以下指令实际上做了什么:
MOV AX,00 MOV AX,[SI+1] MOV [SI],AX
第一条指令没有用,因为第二条指令会覆盖AX
的值。
因为您的数组由 16 位值组成并且 x86 CPU 使用字节寻址(像大多数但不是所有 CPU),第二个值将存储在地址 [SI+2]
,而不是 [SI+1]
.
通过读取 [SI+1]
,您读取了一些(无意义的)值,这些值可以根据数组中的前两个数字计算得出。
并使用最后一条指令覆盖数组中的第一个数字,这对我来说毫无意义。
您永远不会修改 SI
寄存器。如果不修改 SI
寄存器,您以后将永远不会读取数组中的值!
所以您的程序执行以下操作:
Initially, your array contains the values 100h,16Fh,...
You check the value 100h (if it is even or odd)
MOV AX,[SI+1] loads 6F01h into AX
MOV [SI],AX overwrites the first value in the array by 6F01h
You check the value 6F01h (if it is even or odd)
MOV AX,[SI+1] loads 6F6Fh into AX
MOV [SI],AX overwrites the first value in the array by 6F6Fh
You check the value 6F6Fh (if it is even or odd)
MOV AX,[SI+1] loads 6F6Fh into AX
MOV [SI],AX has no effect ...
... because the first element of the array is already 6F6Fh
MOV AX,[SI+1] loads 6F6Fh into AX
...
MOV AX,[SI+1] loads 6F6Fh into AX
...
MOV AX,[SI+1] loads 6F6Fh into AX
...
所以你的程序第一次检查 100h
是偶数还是奇数。这就是你想要的。
第二次检查 6F01h
是偶数还是奇数。第三次、第四次、第五次……第十次……第一百次,它检查 6F6Fh
是偶数还是奇数。这可能是您不想要的。
In order to determine if the hexadecimal no is even, the program would divide the number by 2 and the remainder should be equal to zero.
如果您使用十进制数(没有计算机)并想检查一个数是否可以被 10 整除 - 您是否也可以将该数除以 10 并查看余数?
没有。您会查看最后一位数字并检查它是否为零。
您可以在所有数字系统中执行此操作:
在三进制中,如果最后一位为零,则数字可以被 3 整除;在十六进制系统中,如果最后一位为零,则它可以被 16 整除。在二进制系统中,如果最后一位(= 位)为零,则它可以被二整除。
您可以使用 TEST
指令来检查某个位是零还是一:
指令TEST xxx, 1
检查值xxx
的最后一位是否为0,如果是,则设置零标志(否则清除零标志)。这意味着如果该位为零,JZ
指令(与 JE
相同)将跳转。如果那个位是 1,JNZ
(JNE
) 将跳转。
所以可以用指令TEST AX, 1
替换下面的代码:
MOV DX,0000
MOV BH,00
MOV BL,02
DIV BX
CMP DX,0
而且您甚至可以使用 TEST WORD [SI], 1
直接检查数组中数字中的位,因此您甚至不需要使用 MOV AX, [SI]
将值加载到 AX
注册.