TASM program to take 3-digit input, subtract a number from the input, and output the result

StackOverflow https://stackoverflow.com/questions/21856061

  •  13-10-2022
  •  | 
  •  

Question

Here's my program that I wrote using TASM:

dosseg
.model small
.stack 100h
.data
h1 db 0
t1 db 0
o1 db 0
n db 0
hc db 0
tc db 0
prompt db 'Input 3 digit number: $'
prompt2 db 'Result: $'
lf db 0Dh,0Ah,24h

.code
mov ax,@data
mov ds,ax

lea dx,prompt
mov ah,09h
int 21h

mov ah,01h
int 21h
sub al,30h
mov h1,al

int 21h
sub al,30h
mov t1,al

int 21h
sub al,30h
mov o1,al

cmp h1,00h
jg hn
add n,00h

o:
mov bl,o1
add n,bl
jmp t

hn:
add n,64h
dec h1,01h
cmp h1,00h
jne hn

t:
cmp t1,00h
jg tn
add n,00h
jmp d

tn:
add n,0Ah
dec t1,01h
cmp t1,00h
jg tn
jmp o

d:
sub n,14h
cmp n,64h
jge d2
mov hc,00h

da:
cmp n,0Ah
jge d3
mov tc,00h
jmp dsp

d2:
sub n,64h
add hc,01h
cmp n,64h
jge d2
jmp da

d3:
sub n,0Ah
add tc,01h
cmp n,0Ah
jge d3

dsp:
add hc,30h
add tc,30h
add n,30h

lea dx,lf
mov ah,09h
int 21h

lea dx,prompt2
mov ah,09h
int 21h




mov dl,hc
mov ah,02h
int 21h







mov dl,tc
mov ah,02h
int 21h


mov dl,n
mov ah,02h
int 21h

mov ah,4Ch
int 21h
end

The program displays the difference between the 3-digit input and 20. I had no problem with input which is less than 148. When I input 148 or higher, it doesn't display 128. What do I do?

Was it helpful?

Solution

You are using signed comparisons when converting back the result to digits. If the result is above 128, it will be seen as a negative number and your conversion will fail.

Here is a de-obfuscated and slightly cleaned up version of your code that might work if you change the two buggy jge into jae.

dosseg
.model small
.stack 100h
.data

; input digits
in_1        db 0
in_10       db 0
in_100      db 0

; output digits
out_1       db 0
out_10      db 0
out_100     db 0

; display
d_prompt    db 'Input 3 digit number: $'
d_result    db 'Result: $'
d_crlf      db 0Dh,10,'$'

.code

    mov ax,@data    ; setup data segment
    mov ds,ax

    lea dx,d_prompt ; display prompt
    mov ah,09h
    int 21h

    mov ah,01h      ; read 3 decimal digits and turn them to numbers
    int 21h
    sub al,30h
    mov in_1,al

    int 21h
    sub al,30h
    mov in_10,al

    int 21h
    sub al,30h
    mov in_100,al

    cmp in_1,00h    ; convert them to a byte
    jg add_hundreds

add_units:
    mov bl,in_100
    add out_1,bl
    jmp check_tens

add_hundreds:
    add out_1, 100
    dec in_1
    cmp in_1,00h
    jne add_hundreds

check_tens:
    cmp in_10,00h
    jg add_tens
    jmp compute

add_tens:
    add out_1,10
    dec in_10
    cmp in_10,00h
    jg add_tens
    jmp add_units

compute:
    sub out_1, 20       ; substract 20 to result

    cmp out_1, 100
    jge above_99        ; ***bug*** should use unsigned comparison (jae)

convert_tens:
    cmp out_1,10
    jge between_10_and_99
    jmp display_result

above_99:
    sub out_1,100       ; convert hundreds
    inc out_100 
    cmp out_1,100
    jge above_99        ; ***bug*** should use unsigned comparison (jae)
    jmp convert_tens

between_10_and_99:
    sub out_1,10        ; convert tens
    inc out_10
    cmp out_1,10
    jge between_10_and_99

display_result:
    add out_100,30h     ; convert digits to characters
    add out_10,30h
    add out_1,30h

    lea dx,d_crlf       ; display line break
    mov ah,09h
    int 21h

    lea dx,d_result     ; display result message
    mov ah,09h
    int 21h

    mov dl,out_100      ; display output
    mov ah,02h
    int 21h

    mov dl,out_10
    mov ah,02h
    int 21h

    mov dl,out_1
    mov ah,02h
    int 21h

    mov ah,4Ch      ; terminate program
    int 21h
end

My own go at the problem, to be able to handle numbers > 255
This version will handle anything up to 65535, then roll over to 0.
Negative results (i.e. inputs < 20) are not handled nicely.

.model small
.stack 100h
.data

; value to substract
SUB_VALUE   equ 20

; number of digits
NUM_DIGITS  equ 5

; conversion steps
convert label word
num = 1
rept NUM_DIGITS-1
num = num * 10
endm
rept NUM_DIGITS
    dw  num
num = num / 10
endm

; display
d_prompt    db 'Enter a ',NUM_DIGITS+'0',' digits number: $'
d_result    db 0Dh, 0Ah, 'Result: $'

.code

main:
    mov ax,@data    ; setup data segment
    mov ds, ax

    lea dx,d_prompt ; display prompt
    mov ah, 09h
    int 21h

    mov ah,01h      ; read decimal number
    mov cx, NUM_DIGITS
    lea si, convert
    cld
read:
    mov ah,01h  ; read a digit
    int 21h
    sub al, '0' ; convert to number
    mov dl, al
    xor dh, dh
    lodsw       ; multiply by power of 10
    mul dx
    add bx, ax  ; cumulate result
    loop    read

    sub bx, SUB_VALUE   ; do the substraction

    lea dx,d_result     ; display result message
    mov ah,09h
    int 21h

    mov cx, NUM_DIGITS
    lea si, convert
write:
    lodsw       ; power of 10 divider
    xchg    ax,bx   
    xor dx, dx
    div bx  ; divide result by power of 10
    mov bx, dx  ; store remainder
    mov dl, '0' ; print current digit
    add dl, al
    mov ah,02h
    int 21h
    loop    write

    mov ah,4Ch      ; terminate program
    int 21h
end main

Took me a bit of time to get a DosBox with TASM running, but it reminded me of my days as a DOS hacker :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top