Adding signed numbers in assembly

Ammar Alyousfi picture Ammar Alyousfi · Nov 30, 2013 · Viewed 18.9k times · Source

I want to sum an array elements. This array contains positive and negative numbers.

array db 07, 00, -3, 10, -7, 14, 9, -5, -100


lea ax, data
mov ds, ax
mov es, ax

lea si, array
mov cx, [si] 
mov si, 0002h
xor ax, ax
xor dx, dx 
Addition:
mov bl, [si]
cmp bl, 00h
jl NEGATIVE
xor bh, bh ;
jmp NEXTT
NEGATIVE:
mov bh, 0ffh
NEXTT:
add ax, bx
adc dx, 0
add si, 1
loop Addition

The sum (DX:AX) using this code = 0003 FFAE H which is wrong. I think that the right answer is FFFFFFAE H.

1- How can I fix this problem?

2- How can I know whether a number in a register (AX for example) is positive or negative?

I use emu8086

Answer

nrz picture nrz · Nov 30, 2013

It seems that you don't handle integer overflow appropriately. Carry flag is for unsigned addition and subtraction, but you want signed addition. Overflow flag is for signed addition, it's set always when the sign changes.

Edit: Previous untested code didn't work properly. Here's the corrected (and self-contained) code. Tested with MASM 6.11.

.model small
.stack 4096

.data
array_size      dw 7
array           db -3, 10, -7, 14, 9, -5, -100
numbers         db '0123456789abcdef'

.code
start:
        mov     ax,seg array_size ; lea ax, data
        mov     ds,ax
        mov     es,ax

        mov     cx,[array_size]   ; cx = array size in bytes.
        lea     si,array          ; si points to the array.

; number is computed in dx:bx.

        xor     dx,dx
        xor     bx,bx

adding_loop:
        mov     al,[si]           ; number is read in al.
        cbw                       ; cbw sign-extends al to ax.
        test    ax,ax             ; check the sign of the addend.
        js      negative

positive:                         ; the addend is positive.
        add     bx,ax             ; add.
        adc     dx,0              ; carry.
        jmp     next_number

negative:                         ; the addend is negative.
        neg     ax                ; ax = |ax|.
        sub     bx,ax             ; subtract.
        sbb     dx,0              ; borrow.

next_number:
        inc     si                ; next number.
        loop    adding_loop

; result now in dx:bx.

        mov     ax,bx             ; result now in dx:ax.

; the rest of the code is only for printing.

        push    bx                ; push lower word.
        mov     bx,dx             ; copy the upper word to bx.
        call    print_word_in_hexadecimal

        push    dx                ; push upper word.
        mov     ah,2
        mov     dl,':'
        int     21h               ; print ':'
        pop     dx                ; pop upper word.

        pop     bx                ; pop lower word.
        call    print_word_in_hexadecimal

        mov     ah,4ch
        int     21h

; input:        bx: word to be printed.
; output:       -
print_word_in_hexadecimal:
        push    bx
        push    cx
        push    dx
        mov     cl,4              ; count for rol.
        mov     ch,4              ; 4 nibbles in each word.
next_nibble:
        rol     bx,cl             ; rotate 4 bits to the left.
        push    bx                ; push rotated word.
        and     bx,0fh
        mov     dl,[bx+numbers]
        mov     ah,2              ; print character.
        int     21h
        pop     bx                ; pop rotated word.
        dec     ch
        jnz     next_nibble

        pop     dx
        pop     cx
        pop     bx
        ret
end start

The above code does the signed integer addition for 8-bit values (the 8-bit values are extended to 16-bit values). Register usage has been changed to allow usage of cbw for cleaner code. Adding negative numbers has been converted to subtraction, for simplicity. Hardcoded offset of array (mov si, 0002h, which works only if the array is located at offset 2) has been replaced with lea si,array:

size_of_array dw 7
array         db -3, 10, -7, 14, 9, -5, -100

And the corresponding changes in the code:

lea si, size_of_array ; or you can replace these 2 lines with:
mov cx, [si]          ; 1. mov cx,size_of_array (TASM/MASM syntax).
lea si, array

And how to check if a number is negative or positive? Well, you check the highest bit. For example, as in my code (test does logical AND but doesn't save the result, it only updates the flags):

        test    ax,ax    ; do logical AND for ax,ax but don't save the result.
        js      negative ; jumps if the number is negative.

positive:
        ; the number is positive.
        jmp     my_label

negative:
        ; the number is negative.

my_label: