Test whether a number is a Harshad Number A little code I wrote that will check if the entered 4-digit number is Harshad or not (Harshad number is one which divided by the sum of its digits will leave no remainder, special Harshad is the same but will also work with flipped sum of digits, example - 1729/19 (19 is the sum of digits) and when flipped 1729/91 will leave no remainder as well).

I would love to see how it could become better (I'm still new so was limited with the commands I could've used).

; Harshad.asm - check if input from user (4 digits, 1000-9999) is a Harshad number and if so, check if it's a "special" Harshad number
;
    .MODEL SMALL
    .STACK 100h
    .DATA
RequestStr     DB 'Enter a 4 digit number (1000-9999):',13,10,'$'
IsHarshad      DB ' is a Harshad number.',13,10,'$'
SpecialHarshad DB 'It is also a special Harshad number.',13,10,'$'
NotHarshad     DB ' is not a Harshad number',13,10,'$'
IncorrectInput DB 13,10,'Input is incorrect.',13,10,'$'
Num            DW ? ;Will fit a "word" size (16 bits)
DigitSum       DW ? ;Sum of digits
TEN            DW 10
TENbyte        DB 10
Temp           DB ? ;Used to check if number is also special Harshad during the div process
Temp2          DB ? ;Used with special Harshad div process  
;
     .CODE
     MOV AX,@DATA                ;DS can be written to only through a register
     MOV DS,AX                   ;Set DS to point to data segment
     MOV AH,9                    ;Set print option for INT 21h
     MOV DX,OFFSET RequestStr    ;Set DS:DX to point to RequestString
     INT 21h                     ;Print RequestStr
;
NumberInput:
    ;First digit
    MOV AH,1        ;Set scanning (input) option for INT 21h
    INT 21h         ;Scan first digit
    MOV DX,0
    SUB AL,'0'      ;Converting from ascii value to numeral value
    CMP AL,1        ;First digit must be between 1 and 9 in order for the number to be of 4 digits
    JB WrongInput   ;Otherwise jump to WrongInput label
    CMP AL,9
    JA WrongInput
    MOV AH,0
    MOV DigitSum,AX ;Store only first digit's value at the variable DigitSum
    MUL TEN         ;Multiply AX by 10
    MOV Num,AX
    ;Second digit
    MOV AX,0
    MOV AH,1 
    INT 21h
    SUB AL,'0'
    CMP AL,0
    JB WrongInput
    CMP AL,9
    JA WrongInput
    MOV AH,0
    ADD DigitSum,AX ;Add only second's digit value to DigitSum
    ADD Num,AX      ;Add AX's value (which has been multiplied by 10 with the first digit) to Num variable
    MOV AX,0
    MOV AX,Num      ;Move new Num's value to AX to multiply it by 10
    MUL TEN
    MOV Num,AX
    ;Third digit
    MOV AX,0
    MOV AH,1
    INT 21h
    SUB AL,'0'
    CMP AL,0
    JB WrongInput
    CMP AL,9
    JA WrongInput
    MOV AH,0
    ADD DigitSum,AX
    ADD Num,AX
    MOV AX,0
    MOV AX,Num
    MUL TEN
    MOV Num,AX
    ;Forth digit
    MOV AX,0
    MOV AH,1 
    INT 21h
    SUB AL,'0'
    CMP AL,0
    JB WrongInput
    CMP AL,9
    JA WrongInput
    MOV AH,0
    ADD DigitSum,AX ;Now DigitSum contains the sum of each of the 4 digits in the number
    ADD Num,AX ;Num contains full 4 digits number
    JMP CheckHarshad    
WrongInput:      
    MOV AH,9
    MOV DX,OFFSET IncorrectInput
    INT 21h
    JMP CodeEnd
CheckHarshad:
    MOV AX,0
    MOV DX,0
    MOV AX,Num
    DIV DigitSum ;Number will be stored in AX and the remainder in DX
    CMP DX,0 ;Check if there is remainder or not
    JE CheckSpecialHarshad
    MOV AH,9
    MOV DX,OFFSET NotHarshad 
    INT 21h
    JMP CodeEnd
CheckSpecialHarshad:
    MOV AH,9
    MOV DX, OFFSET IsHarshad
    INT 21h
    MOV AX,0
    MOV AX,DigitSum
    DIV TENbyte
    MOV Temp,AL
    MOV Temp2,AH
    MOV AX,0
    MOV AL,Temp2
    MUL TENbyte
    ADD AL,Temp
    MOV Temp2,AL ;Temp2 now has the DigitSum number flipped
    MOV AX,0
    MOV AX,Num
    DIV Temp2
    CMP AH,0
    JNE CodeEnd
    MOV DX,OFFSET SpecialHarshad
    MOV AH,9
    INT 21h
CodeEnd:
    MOV AH,4Ch
    INT 21h
    END
Written for NASM


Your program is a little hard to follow, mostly due to poor formatting. There is a lot of unnecessary duplication too and the user has no opportunity for correcting mistakes. The following prologue will address these initial criteria;


Prompt operator for what is required.
Use a function that allows the user to correct mistakes.
Test that entry is 4 characters long and the first digit is not zero.




      org   0x100

      DOS   equ 21H
     SHOW   equ  9
 BUFFERED   equ 10  ; Buffered input
   OUTCHR   equ  2
   GETCHR   equ  8


Begin:  mov ah, SHOW        ; Function 9 display string terminated with '$'
        mov dx, Prompt
        int DOS

        mov ah, BUFFERED    ; Function 10 Get buffered input
        mov dx, Entry
        int DOS

; Test that your criteria of 4 character entry and first digit not zero has been met.

        cld                 ; Make sure SI auto-increments
        mov si, dx
        inc si              ; Point to number of characters entered
        lodsb
        or  al, al
        jz  Err             ; You might want to put some sort of prompting text here
        cmp al, 4   
        jnz Err
        cmp byte [si], '1'
        jae Evaluate

Err:    mov ah, SHOW        ; Function 9 again
        mov dx, ErrTxt
        int DOS
        ret                 ; Return to DOS


You do have these elements in your program, but I think you'll agree when there are in one place it's a lot easier to recognize which error testing mechanism has been implemented. Notice too, formatting is monumentally important, especially in ASSM.

Now we are ready to do the calculations and because we're not going to be using any DOS functions, there is a little more freedom in which registers we can use and for what. The criteria now becomes, establish a binary value of our entry and binary total of all digits.

Evaluate:

    ; AX = Working register, CX = character count

        movzx   cx, al      ; Move character count into CX
        xor     dx, dx      ; DX will be binary representation of input
        mov     bx, dx      ; BL will be total of digits
        mov     ax, dx

  .get: lodsb           ; Read character from input string
        cmp     al, '0'
        jb      Err
        cmp     al, '9'
        ja      Err

       and      ax, 1111b   ; Could be SUB AL,'0' too.
       add      bl, al      ; Bump total of digits
       xchg     ax, dx
       imul     ax, 10
       add      dx, ax
       loop     .get

     ; Now DX = Binary equivalent and BL divisor

        xor     ax, ax
        xchg    ax, dx
        push    ax          ; Going to need this again to determine if Special
        idiv    bx
        or      dl, dl      ; Determine if value is Harshad or not.


From this point I'd pretty much be doing the same as you have except there is still no need to address anything in memory other than prompting text as everything you need is on the stack and BL. Let us know what you come up with then we'll compare it with what I have.