Събиране на две числа, за да се получи двуцифрено число

Искам да събера две предварително определени стойности заедно и да произведа резултата. Това, което моят код прави в момента, е, че събира 16 и 6 заедно, което трябва да отпечата 22. Той обаче отпечатва 2... Не съм много сигурен как да коригирам това...

Ето кода:

data    segment                         ; data segment. Keyword db means define byte. You can also define word (dw)
        numA    db  16                  ;Define first variable
        numB    db  06                  ;Define second variable
        StrMsg  db 'The answer is $'    ;return message to the user
        leng    db 1                    ;length of the charachters - this value will be overwritten
data    ends

                                        ; stack segment
stack1  segment stack       
        db  100 dup(?)                  ; This is the stack of 100 bytes
stack1  ends


code    segment
        assume  cs:code, ds:data, ss:stack1

start: 
                                        ;Perform initialization 
        mov ax, data                    ;Put the starting address of the data segment into the ax register (must do this first)
        mov ds, ax                      ;Put the starting address of the data segment into the ds register (where it belongs)

        mov ax, stack1                  ;Put the starting address of the stack into the ax register (must do this first)
        mov ss, ax                      ;Put the starting address of the stack segment into the ss register (where it belongs)

mov al, numA        ;move numA to ax
    add al, numB        ;ax contains numa + numb
    mov dl, al          ;move result to dl for display                      

    lea dx, StrMsg      ;load message to display the result to the user
    mov ah, 9h          ;display string subroutine 
    int 21h             ;interrupt for MS-DOS routine   

    add dl, 30h         ;Add 30h for ASCII table offset 
    mov ah, 2h          ;Store interrupt code in ah to display results in dl
    int 21h             ;display character in dl as translated by ascii code

mov ah, 4ch                     ;Set up code to specify return to dos
        int 21h                         ;Interpt number 21 (Return control to dos prompt)

code    ends

end     start

person user2961971    schedule 31.10.2014    source източник
comment
Тъй като печатате само 1 знак, не трябва да се изненадвате. За да работите с двуцифрени числа, може да искате да отпечатате десетиците и единиците една след друга. Според математиката в началното училище това би било частното и остатъкът от деленето на 10.   -  person Jester    schedule 31.10.2014
comment
Моля, добавете таг за асемблера, който използвате ([tasm] или [masm])   -  person rkhb    schedule 31.10.2014


Отговори (1)


Ако наистина искате да получите само двуцифрено десетично число (както подсказва заглавието), можете да използвате AAM:

data    segment                         ; data segment. Keyword db means define byte. You can also define word (dw)
        numA    db  16                  ;Define first variable
        numB    db  06                  ;Define second variable
        StrMsg  db 'The answer is $'    ;return message to the user
        leng    db 1                    ;length of the charachters - this value will be overwritten
data    ends

                                        ; stack segment
stack1  segment stack
        db  100 dup(?)                  ; This is the stack of 100 bytes
stack1  ends


code    segment
        assume  cs:code, ds:data, ss:stack1

start:
                        ;Perform initialization
    mov ax, data        ;Put the starting address of the data segment into the ax register (must do this first)
    mov ds, ax          ;Put the starting address of the data segment into the ds register (where it belongs)

    mov ax, stack1      ;Put the starting address of the stack into the ax register (must do this first)
    mov ss, ax          ;Put the starting address of the stack segment into the ss register (where it belongs)

    lea dx, StrMsg      ;load message to display the result to the user
    mov ah, 9h          ;display string subroutine
    int 21h             ;interrupt for MS-DOS routine

    mov al, numA        ;move numA to al
    add al, numB        ;al contains numa + numb

    lea di, StrMsg      ; Place for target string (The old value of StrMsg isn't used anymore)
    aam                 ; AL => AH (first dec. digit) AL (second dec. digit) (unpacked BCD)
    or ax, 3030h                 ; Convert both digits to ASCII
    mov BYTE PTR [di], ah        ; Store first digit
    mov BYTE PTR [di+1], al      ; Store second digit
    mov BYTE PTR [di+2], '$'     ; Store termination character for 'int 21h fn 09h'

    lea dx, StrMsg      ;load message to display the result to the user
    mov ah, 9h          ;display string subroutine
    int 21h             ;interrupt for MS-DOS routine

    mov ah, 4ch         ;Set up code to specify return to dos
    int 21h             ;Interpt number 21 (Return control to dos prompt)

code    ends

end     start

Ако също искате да получите трицифрено десетично число, можете да изолирате цифрите с две деления. Първо разделете на 100 и ще получите първата цифра като резултат. След това разделете остатъка на 10 и ще получите втората цифра, докато третата цифра е в остатъка:

data    segment                         ; data segment. Keyword db means define byte. You can also define word (dw)
        numA    db  16                  ;Define first variable
        numB    db  06                  ;Define second variable
        StrMsg  db 'The answer is $'    ;return message to the user
        leng    db 1                    ;length of the charachters - this value will be overwritten
data    ends

                                        ; stack segment
stack1  segment stack
        db  100 dup(?)                  ; This is the stack of 100 bytes
stack1  ends


code    segment
        assume  cs:code, ds:data, ss:stack1

start:
                        ;Perform initialization
    mov ax, data        ;Put the starting address of the data segment into the ax register (must do this first)
    mov ds, ax          ;Put the starting address of the data segment into the ds register (where it belongs)

    mov ax, stack1      ;Put the starting address of the stack into the ax register (must do this first)
    mov ss, ax          ;Put the starting address of the stack segment into the ss register (where it belongs)

    lea dx, StrMsg      ;load message to display the result to the user
    mov ah, 9h          ;display string subroutine
    int 21h             ;interrupt for MS-DOS routine

    mov al, numA        ;move numA to ax
    add al, numB        ;ax contains numa + numb
    mov dl, al          ;move result to dl for display

    lea di, StrMsg      ; Place for target string (The old value of StrMsg isn't used anymore)
    call al2dec

    lea dx, StrMsg      ;load message to display the result to the user
    mov ah, 9h          ;display string subroutine
    int 21h             ;interrupt for MS-DOS routine

    mov ah, 4ch         ;Set up code to specify return to dos
    int 21h             ;Interpt number 21 (Return control to dos prompt)

al2dec PROC             ; Args: AL register to convert, DS:DI pointer to target string
    mov bl, 100
    xor ah, ah          ; Clear AH for division
    div bl              ; AL = AX / BL remainder AH
    or al, 30h          ; Convert result to ASCII
    mov BYTE PTR [di], al        ; Store as first digit

    shr ax, 8           ; Shift remainder into AL, clear AH
    mov bl, 10
    div bl              ; AL = AX / BL remainder AH
    or al, 30h          ; Convert result to ASCII
    mov BYTE PTR [di+1], al      ; Store as second digit

    or ah, 30h          ; Convert remainder to ASCII
    mov BYTE PTR [di+2], ah      ; Store as third digit

    mov BYTE PTR [di+3], '$'     ; Store at last termination character for 'int 21h fn 09h'
    ret
al2dec ENDP             ; DS:DI contains string with decimal digits

code    ends

end     start

Ако ви притесняват водещите нули, можете да изолирате цифрите в обратен ред, като многократно разделите на 10. Това е и най-използваният метод, ако искате да конвертирате по-големи числа:

al2dec PROC                         ; Args: AL register to convert, DS:DI pointer to target string
    mov bl, 10                      ; Base 10 -> divisor
    xor cx, cx                      ; CX=0 (number of digits)

  al2dec_loop_1:                    ; 1st loop
    xor ah, ah                      ; Clear AH for division (don't forget it!)
    div bl                          ; AL = AX / BL   Remainder AH
    push ax                         ; Push remainder for LIFO in Loop_2
    add cl, 1                       ; Equivalent to 'inc cl'
    test al, al                     ; AL = 0?
    jnz al2dec_loop_1               ; No: once more
  al2dec_loop_2:                    ; 2nd loop
    pop ax                          ; Get back pushed digits
    or ah, 00110000b                ; Conversion to ASCII
    mov BYTE PTR [di], ah                    ; Store only AH to [DS:DI] (DI is a pointer to a string)
    add di, 1
    loop al2dec_loop_2              ; Until there are no digits left

    mov BYTE PTR [di], '$'                   ; Store termination character for 'int 21h fn 09h'
    ret                             ; Ret: DS:DI contains decimal '$'-terminated ASCII-String
al2dec ENDP
person rkhb    schedule 31.10.2014
comment
Няма причина да използвате add cl, 1. Ако оптимизирате за размер на кода с инструкции като loop, трябва също да използвате еднобайтов inc cx. Особено защото нулирате CX и го използвате като брояч на цикли, така че за човешка четливост работата с CX навсякъде би била по-ясна. Но досега това изглежда като разумен каноничен дубликат за 2-цифрени/многоцифрени въпроси на DOS. (Въпреки това не харесвам 2 цикъла натискане/изскачане, той е раздут в сравнение със простото съхраняване в паметта от последния към първия, започвайки от края на буфера, особено когато искате да печатате само с едно извикване) - person Peter Cordes; 09.04.2019