Adding signed numbers in assembly
addition, assembly, signed, x86, x86-16
Solution
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:
Problem
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