Reputation: 21
I have a bug in one of my loops and I can't fix it. It is part of my HW assignment for school. I have an array, with 20 elements, and I need to multiply every element by 2, using bit shift. It kind of works, but every time I have a carry, it is adding 2 to the previous element in the array, instead of one. I can't propagate the carry through the array properly. This is my first semester with assembly, so I appreciate your help. Also, please keep it simple if you can. Thank you.
This is what I want: 0000000009 ==> 0000000018 0000000099 ==> 0000000198
This is what I am getting. 0000000009 ==> 0000000028 0000000099 ==> 00000002108
Here is the code.
ARR1 DB 20 DUP (0)
MULTIPLYING PROC
MOV AX, 0
MOV CX, 19
.WHILE CX != 0
MOV DI, CX
MOV AL, [DIGIT_ARR1+DI]
;MOV BL, 2
;MUL BL
SHL AX, 1
.IF AX > 9 ; IF THE NEW DIGIT IS LARGER THAN 9
SUB AX, 10
MOV AH, 0
MOV [DIGIT_ARR1+DI], AL
DEC DI
ADD [DIGIT_ARR1+DI], 1
.ELSEIF
MOV [DIGIT_ARR1+DI], AL ; IF IT IS LESS THAN 9, THEN JUST INSERT IT BACK INTO THE ARRAY
.ENDIF
DEC CX
.ENDW
RET
MULTIPLYING ENDP
Upvotes: 0
Views: 1497
Reputation: 21
So it turned that Phil was correct. I was rewriting my own data. The trick was to read the value, do the multiplication using bit shift, add the carry (if any) and only then write back to the array. This way I can multiply each element, by two and not corrupt my data.
NOTE FOR BEGINNERS LIKE ME: bit shift will only multiply by two, so if you need to multiply by something else, use mul or imul. Also, bit shift to the right will divide by two. The loop below will multiply BCD in array by two. Division works the same way, only make sure you process the array the other way and add 10 to each next digit when you have a carry. You will also have to make sure you don't add the carry once you reach the end of the array. Assembly language doesn't check if you are out of bounds of the array.
MULTIPLYING PROC
PUSH CX
PUSH AX
MOV CARRY, 0 ; START WITH EMPTY CARRY FLAG
MOV CX, 19 ; ARRAY SIZE
.WHILE CX > 0
MOV DI, CX ; GET ELEMENT ADDRESS
MOV AL, [ARR1+DI] ; READ THE ELEMENT
SHL AL, 1 ; DOUBLING THE DIGIT
ADD AL, CARRY ; ADD THE CARRY FLAG
MOV CARRY, 0 ; CLEAR THE CARRY FLAG
.IF AL > 9 ; IF THE NEW DIGIT IS LARGER THAN 9
SUB AL, 10
MOV CARRY, 1 ; SET CARRY FLAG
MOV [ARR1+DI], AL ; INSERTING THE DOUBLED DIGIT BACK TO THE ARRAY
.ELSEIF
MOV [DIGIT_ARR1+DI], AL ; IF IT IS LESS THAN 9, INSERT IT BACK INTO THE ARRAY
MOV CARRY, 0
.ENDIF
DEC CX
.ENDW ; END OF MULTIPLICATION PROC
POP AX
POP CX
RET
MULTIPLYING ENDP
Upvotes: 1
Reputation: 2313
I think the problem is that you're writing back to the same array of addresses that you're reading from. When you carry, it is corrupting the calculation.
e.g. From: 99
Positon 19 = 9
9*2 = 18 (set position 19 to 8, increment position 18 to 10)
Position 18 = 10
10*2 = 20 (set position 18 to 10, increment position 17 to 1)
Position 17 = 1
1*2 = 2 (set position 17 to 2)
Result: 2108
But you still need to do more work because even with empty destination addresses you get
Positon 19 = 9
9*2 = 18 (set position 19 to 8, increment position 18 to 1)
Position 18 = 9
9*2 = 18 (set position 18 to 8, increment position 17 to 1)
Position 17 = 1
1*2 = 2 (set position 17 to 2)
Result: 288
You need to add the 8 to the 1 at position 18 so you get 9. And you dont do a 3rd multiplication because position 17 is empty in the source address array. I hope this makes sense.
You shouldn't get any digit overflow errors when multiplying by 2 like this, but you may need to handle it when multiplying by larger numbers.
Upvotes: 0