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 '-'.