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. If not, then it is an odd number. Initially, my plan was to I have a variable or register that will increment when a hexadecimal is proven to be even. Then afterwards I would just subtract the number of even nos. to five to get the number of odd nos. But since I had to use three registers to hold the dividend and divisor (AX & BX
), plus another for the array counter (CX
), I ran out of registers to hold the value of the "even counter".
I revised the program so that it can still satisfy the instruction (see title). This time, the program would display the character E
for even and O
for odd. My problem now is the program only recognizes up to the second array item, meaning the value of SI
remains the same and does not increment after the second array item. This makes the output of the program EOOOO
instead of EOOOE
.
My questions are:
1.) How will I increment the value of SI
from its memory and pass it to AX
to be divided
2.) Is it possible to make my initial plan work? If yes, what register can I use to hold the "even counter"
Here is the code:
.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
.
You seem not to be fully aware what the following instructions in your code actually do:
MOV AX,00 MOV AX,[SI+1] MOV [SI],AX
The first instruction is useless because the second instruction will overwrite the value of AX
.
Because your array consists of 16-bit values and x86 CPUs use byte-wise addressing (like most but not all CPUs), the second value will be stored at the address [SI+2]
, not at [SI+1]
.
By reading [SI+1]
, you read some (non-sense) value which can be calculated from the first two numbers in the array.
And using the last instruction you overwrite the first number in the array, which makes no sense to me.
You never modify the SI
register. Without modifying the SI
register, you will never read values later in the array!
So what your program does is the following:
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
...
So the first time your program checks if 100h
is even or odd. This is what you want.
The second time it checks if 6F01h
is even or odd. And the third, fourth, fifth ... tenth ... hundredth time, it checks if 6F6Fh
is even or odd. This is what you probably don't want.
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.
If you work with decimal numbers (without a computer) and want to check if a number is divisible by ten - would you also divide the number by ten and look at the remainder?
No. You would look at the last digit and check if it is zero.
You can do this in all numeral systems:
In ternary system, a number is divisible by 3 if the last digit is zero; in hexadecimal system it is divisible by 16 if the last digit is zero. And in binary system it is divisible by two if the last digit (= bit) is zero.
You can use the TEST
instruction to check if a bit is zero or one:
The instruction TEST xxx, 1
checks if the last bit of the value xxx
is 0 and set the zero flag if this is the case (and clear the zero flag otherwise). This means that the JZ
instruction (which is the same as JE
) will jump if that bit was zero. And JNZ
(JNE
) will jump if that bit was one.
So you can replace the following code by the instruction TEST AX, 1
:
MOV DX,0000
MOV BH,00
MOV BL,02
DIV BX
CMP DX,0
And you can even use TEST WORD [SI], 1
to directly check the bit in a number from the array, so you don't even need to use MOV AX, [SI]
to load the value into the AX
register.