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?
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 :)