Search code examples
arraysassemblyx86-16multiplicationemu8086

Product of array elements


In this exercise, I need to find the product of the array elements. I wrote the following program but it doesn't seem to work. The correct answer is -36288, but I keep getting 49.

The result I'm after is : -7 x 8 x -9 x 6 x 6 x -2. The number 3 in the array is be ignored.

include 'emu8086.inc'

ORG 100h
mov bx, 0
MOV di, 0 
cmp b [di+bx], 3 
je skip
skip: add di,1
cmp di, 7
jle qemer 
qemer: mov Al, b [di + bx]
inc di 
imul b [di+bx] 

CALL pthis
DB 13, 10, 'Result:', 0
CALL print_num; print number in AX.
RET; return to operating system.
b DB 3,-7,8,-9,6,3,6,-2
DEFINE_SCAN_NUM
DEFINE_PRINT_STRING
DEFINE_PRINT_NUM
DEFINE_PRINT_NUM_UNS; required for print_num.
DEFINE_PTHIS
DEFINE_CLEAR_SCREEN
END; 

Solution

  • Traversing the array with a loop

    This is how your basic loop that traverses the array looks like. I'm sure your teacher's loop will look very similar to this one.

      xor  si, si          ; Clears offset into the array
    More:
      mov  al, array [si]  ; Reads an element
    
      ; act on the value
    
      inc  si              ; Next byte-sized element
      cmp  si, 8           ; Array has 8 bytes
      jb   More            ; Repeat for all value less than 8
    

    And because multiplication is commutative, you could just as well traverse the array starting at the end, with the 8th element being at offset +7:

      mov  si, 7           ; Offset into the array to the last element
    More:
      mov  al, array [si]  ; Reads an element
    
      ; act on the value
    
      dec  si              ; Next byte-sized element
      jns  More            ; Repeat for all positive values
    

    What kind of multiplication to use?

    The numbers are signed numbers, so you'll have to use the signed multiplication imul.
    Because the product of the numbers -7, 8, -9, 6, 6, and -2 is -36288, you'll have to use the word-sized version of imul. This means that the signed bytes that you read from the array must be sign-extended into AX before using them in the multiplication.
    And skipping the included numbers 3 is just an added complexity.

      mov  bx, 1           ; Initialize the result with the product-neutral value
      xor  si, si
    More:
      mov  al, array [si]
      cmp  al, 3           ; Don't use the number 3
      je   Skip
      cbw                  ; Sign-extend AL into AX
      imul bx              ; AX * BX -> DX:AX = {-7, -56, 504, 3024, 18144, -36288}
      mov  bx, ax          ; Update the result in BX
    Skip:
      inc  si
      cmp  si, 8
      jb   More
    

    Printing this result is tricky

    You are calling print_num for this, but this will fail because the result is outside the valid range for a signed word [-32768, +32767]. The screen would show you "29248".
    The trick here is to use the unsigned version print_num_uns after we have outputted a minus sign and have negated the number in AX:

      call pthis
      db   13, 10, 'Result:', 0
      putc '-'
      mov  ax, bx
      neg  ax
      call print_num_uns
      ret
    
    array db 3, -7, 8, -9, 6, 3, 6, -2
    DEFINE_SCAN_NUM
    DEFINE_PRINT_STRING
    DEFINE_PRINT_NUM
    DEFINE_PRINT_NUM_UNS
    DEFINE_PTHIS
    DEFINE_CLEAR_SCREEN
    END