Reputation:
I wrote a program to get the smallest number in an array, but I can't print it on the screen :(( I think the problem is converting it to ASCII.
.model small
.stack 100h
.data
x db 0,5,-1,4,2 ;my array
min db 0 ;variable to store the smallest number
msg db "The min number is: $"
.code
main PROC
mov ax,@data
mov ds,ax
xor cx,cx
mov cl,5 ;set count to 5
mov si,0 ;start at index 0
L1:
mov dl,x[si] ;can't compare memory to memory so I moved x[si] to dl
cmp min,dl ;checks to see if the value in dl is smaller than
;value in min
JNB no
mov min,dl
no:
inc si
loop L1
mov ah,09
mov dx,offset msg ;print the message
int 21h
cmp min,0 ;check if number is negative or positive
JB minus
mov ah,02
mov dl,min
int 21h
minus: ;if minus print the minus sign
mov ah,02
mov dl,'-'
int 21h
*mov ah,02
mov dl,min
or dl,30h ;here's my error can't print value of min
int 21h*
mov ah,04ch ;exit code
int 21h
main ENDP
END main
Also if anyone has good source or a book of learning 80386 assembly protected mode please mention it here :))
Upvotes: 0
Views: 4645
Reputation: 365832
Related: on a modern x86 CPU in 16-bit mode, you can use SSE4.1 phminposuw
with a range-shift to make it work on signed inputs. You can find the min out of 8 elements in one instruction: x86 Assembly - 2 largest values out of 4 given numbers. Load signed bytes using pmovsxbw xmm0, [num]
.
A more-efficient way to implement the min-finding loop avoids the slow loop
instruction, and avoids taken branches (other than the loop branch) when there's no new min. I could have made the code smaller by using loop
, and/or by using a normally-taken jge
to skip over an instruction inside the loop, instead of falling through into code that's normally not run.
Related: Assembly program that finds second largest value in array. I used a similar loop structure there.
Comparing against an end-pointer is efficient, whether it's a constant or in a register. As an immediate, it saves instructions outside the loop. We also don't need to tie up CX
with a loop counter; we already have the pointer in SI
.
The main point of this answer is the more compact code for printing a leading -
, like I mentioned in comments on @Ahtisham's answer. See the 2nd part of main
below.
.model small
.stack 100h
.data
num db 0,5,-1,4,2 ;my array
numEnd:
numSize = numEnd - num
msg db "The min number is: $"
.code
main PROC
mov ax, @data
mov ds, ax
mov si, OFFSET num
mov bl, [si] ; bl = min
calMin: ; do {
cmp si, OFFSET numEnd-1
jae endloop ; if (p >= end-1) break;
inc si ; p++
cmp bl, [si]
jle calMin ; if (*p <= min) continue; signed compare
; on new min, fall through and update BL before continuing
mov bl, [si] ; min = *p
jmp calMin ; } while(1);
endloop:
;;; BL = min. Do whatever you want with it.
Now we have the min of the array in bl
.
Normally you'd load into a register instead of using multiple loads, but mov al, [si]
only runs rarely for most inputs. Reloading the same value is fast (because of cache) so saving an instruction in the common-case loop is a win even if it means an extra load when we find a new min.
Given a single-digit signed min
in bl
, we can print it (with a -
if it's negative):
; we could print the message before the loop
; if we wanted to avoid clobbering registers.
mov ah, 09h ; print a message first
mov dx, offset msg
int 21h ; al = write string to stdout(ds:dx)
mov dl, bl ; in case it's positive
neg bl ; bl = 0 - bl setting flags accordingly
jle posNum ; if (0 <= num) skip the leading '-'
mov ah, 02h
mov dl, '-' ; print minus symbol if negative number
int 21h ; al = print char to stdout(dl)
mov dl, bl ; the negated value is positive, print it
posNum:
; absolute value of single-digit number in DL
mov ah, 02h
add dl, '0'
int 21h ; al = print char to stdout(dl)
exit:
mov ax, 04c00h ; AL = 0 (exit status), AH = 4C (Exit function)
int 21h
main ENDP
END main
You don't need to test SF
and ZF
separately with separate js
and jz
instructions. I used jle
after a neg
to fall through if the original number was negative, because it sets flags based on 0 - num
. i.e. jle
is taken if 0 <= num
, i.e. num
is non-negative and we shouldn't print a '-'
.
I could have done
test bl, bl
jge posNum
because test same,same
sets flags identically to cmp bl, 0
. And of course jge
is taken for numbers that are greater than or equal to zero.
Note that 0 - 128
does overflow, so just testing SF after neg
isn't equivalent to jle
. jle
is correct, js
isn't.
But our printing only handles single-digit integers in the first place. If that's what you have, use one of the many multi-digit number functions to print the absolute value as an unsigned integer after printing the optional '-'
.
Upvotes: 1
Reputation: 10136
You code has two problems ( apart from displaying a negative number )
1.Placing zero in NUM variable
What if your array contains non-zero numbers like for eg: 5, 4, 7, 1
it should print 1 as its the minimum number but your code will print 0 which is not even present in the array.
2.Using JNB and JB Instructions
These Instruction are only used for positive integer here have a look JNB JB. You have to use JNG and JG as your array contains negative number.
Following is the program to check for minimum number in an array ( Doesn't matter if it contains negative or positive number it will work in both the cases and it also shows how to print negative number ):
.model small
.stack 100h
.data
num db 7,5,3,4,2 ;my array
msg db "The min number is: $"
.code
main PROC
mov ax,@data
mov ds,ax
mov ax, 0
mov bl, num [0] ; store first element of array in bl
mov cx, 4
mov si, 1 ; index of second element
calMin:
mov al, num [si]
cmp bl, al
jng continue ; jng is used for signed numbers
mov bl, al ; exchange values if smaller
continue:
inc si
loop calMin
mov ah, 09h
mov dx, offset msg
int 21h
mov cl, bl
neg cl ; 2's complement the min number ( to check if its negative or positive number )
js posNum ; jmp to posNum if sign flag is set
mov bl, cl
jz posNum
negNum:
mov ah, 02h
mov dl, '-' ; print minus symbol if negative number
int 21h
posNum:
mov ah, 02h
mov dl, bl
add dl, 48
int 21h
exit:
mov ah,04ch
int 21h
main ENDP
END main
Upvotes: 1