News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Entering Data into Arrays

Started by veronicak5678, November 26, 2009, 05:22:58 AM

Previous topic - Next topic

veronicak5678

I need to get two 10-digit numbers from the user and put them into two 20 byte-long byte arrays. My professor suggested we get them in pieces, asking for the first 4, the second four, and the last 2 so we can use 'getdec.' I am trying to do this and divide by 10 to get the remainder into the arrays. I can't see why this gives me a divide overflow.


INCLUDELIB IO.LIB
INCLUDE PCMAC.INC
EXTRN NEWLINE:FAR
EXTRN GETDEC$:FAR
EXTRN PUTDEC$:FAR
;==============================================================================
.MODEL SMALL
.586
.STACK 1000h
;==============================================================================
.DATA
ARR1 DB 20 DUP (0)
ARR2 DB 20 DUP (0)
ARR3 DB 20 DUP (0)
INPUT1A DB 'Enter the first 4 digits of number 1  ', '$'
INPUT2A DB 'Enter the second 4 digits of number 1 ', '$'
INPUT3A DB 'Enter the last 2 digits of number 1   ', '$'
INPUT1B DB 'Enter the first 4 digits of number 2  ', '$'
INPUT2B DB 'Enter the second 4 digits of number 2 ', '$'
INPUT3B DB 'Enter the last 2 digits of number 2   ', '$'
X DW 0
;==============================================================================
.CODE
MAIN PROC
      MOV     AX,@DATA            ;SET DS AND ES REGISTERS
        MOV     DS,AX               ;TO POINT TO DGROUP
      MOV     ES,AX

SPUTSTR INPUT1A
CALL GETDEC$
mov x, ax
MOV BL, 10
SUB DI, DI
MOV CX, 4
CALL FILL1

CALL NEWLINE
SPUTSTR INPUT2A
CALL GETDEC$
mov x, ax
MOV DI, 4
MOV CX, 4
CALL FILL1

CALL NEWLINE
SPUTSTR INPUT3A
CALL GETDEC$
mov x, ax
MOV DI, 8
MOV CX, 2
CALL FILL1

CALL NEWLINE
SPUTSTR INPUT1B
CALL GETDEC$ 
mov x, ax
MOV BL, 10
SUB DI, DI
MOV CX, 4
CALL FILL2

CALL NEWLINE
SPUTSTR INPUT2B
CALL GETDEC$ 
mov x, ax
MOV DI, 4
MOV CX, 4
CALL FILL2

CALL NEWLINE
SPUTSTR INPUT3B
CALL GETDEC$  
mov x, ax
MOV DI, 8
MOV CX, 2
CALL FILL2

SUB DI, DI
      MOV     DI,OFFSET ARR1
CALL DISPLAY

SUB DI, DI
      MOV     DI,OFFSET ARR2
CALL DISPLAY

       MOV     AX,4C00h
       INT     21h
MAIN    ENDP
;---------------------------------------------------
FILL1    PROC    NEAR

FILLLOOP:
IDIV BL
IDIV BL
IDIV BL
        MOV     ARR1[DI],AL
MOV AX, X
SHL AX,1
MOV X, AX
INC DI
LOOP FILLLOOP
RET
FILL1    ENDP
;----------------------------------------------------
FILL2    PROC    NEAR

FILLLOOP2:
IDIV BL
IDIV BL
IDIV BL
        MOV     ARR2[DI],AL
MOV AX, X
SHL AX,1
MOV X, AX
INC DI
LOOP FILLLOOP2
RET
FILL2    ENDP
;----------------------------------------------------
DISPLAY PROC NEAR
        CALL    NEWLINE
      MOV     CX,20
DLOOP:
        MOV     AL,[DI]
      MOV     AH,0
CALL PUTDEC$
        INC     DI
     LOOP    DLOOP
RET
DISPLAY   ENDP
;-----------------------------
END     MAIN

dedndave

divide overflow happens when the quotient is too large for the targeted register
it usually happens when dividing larger numbers by smaller ones
you are using IDIV BL - one problem with IDIV is it reduces the size by one bit because of the sign
another problem is dividing by a byte value means the quotient has to fit into the AL register
this code has another problem

        IDIV    BL
        IDIV    BL
        IDIV    BL

the IDIV BL instructions divide the value in AX by BL, and place the quotient in AL and the remainder in AH
a subsequent IDIV BL divides (256 * remainder + quotient) by BL from the previous IDIV BL
you never move the data out to safe registers prior to the next IDIV or zero the AH register
you can extend the range of the quotient by dividing by a word size operand using IDIV BX, for example
in that case, the value in DX:AX is divided by BX
if you are dividing a word value, place it in AX and zero the DX register prior to DIV
the quotient will be in the AX register and the remainder in DX
if IDIV'ing by 10, the largest positive value you may use as a dividend in DX:AX is 327670
using DIV (unsigned division), it could be as large as 655350

i would use an approach entirely different from what your teacher describes
rather than inputing numeric values with GETDEC, why not get string values from the user ?
they are already divided by 10 - all you have to do is convert each digit from ASCII to binary - very simple
and, they can enter all the digits in one line   :bg

veronicak5678

What do you mean, they are already divided by 10? We haven't done anything with strings before, and our professor said it would be too complicated to have them user input the numbers as strings. Of course, he has steered us wrong before...

dedndave

well, if it takes in an ASCII string like "3463495435765757234", the digits are already split up for you
place the string directly into the array and convert it from ASCII characters to binary values
if the user enters a non-numeric character, tell them to re-enter the value
(actually, i can write an input routine that only allows numbers and enter - lol)

MichaelW

#4
I have not tried to implement it, but I think it can be done as your professor suggested.

For the DIV and IDIV instructions with an 8-bit divisor, you get a divide overflow whenever the quotient will not fit into AL. For the IDIV instruction this will happen when AH >= (2 * the divisor). For the DIV instruction this will happen when AH >= the divisor.

In your fill loops, beyond the repeated IDIV BL I don't understand why you included the SHL AX, 1.

Edit:

I don't know what the arrays will ultimately be used for, but since you are dividing by 10 and taking the remainder I'm assuming that the array is supposed to be loaded with decimal digits, so it effectively forms a string.

I have determined that the array can reasonably be loaded with GETDEC. To avoid the overflow problem I used a 16-bit divisor, for which the dividend is DX:AX, and zeroed DX before each division. Note that the digit values are extracted in reverse order (relative to the order in which they are normally written) with the first division extracting the least significant digit, so your array indexing must allow for this. After each division the remainder is a digit value, in DL. If the above assumption is correct, then you need to add the ASCII character code for "0" to the digit value to convert it to a decimal digit.

eschew obfuscation

veronicak5678

Hi Michael-

I used the shifts to get rid of the first digit, which I had already stored. The idea is we are going to multiply the two arrays together into a third 20 byte-long array using the Russian peasant method.

MichaelW

QuoteThe idea is we are going to multiply the two arrays together into a third 20 byte-long array using the Russian peasant method.

I take this to mean that the arrays should contain digit values instead of decimal digits.

QuoteI used the shifts to get rid of the first digit, which I had already stored.

The division operation removes the digits:

123 / 10 = 12 remainder 3
12 / 10 = 1 remainder 2
1 / 10 = 0 remainder 1
eschew obfuscation

veronicak5678

I thought I would enter 4 digits (1234), then
1234/10 for 123
123/10 for 12
12/10 for 1
put 1 into array
shl 1234 for 2340

and do the same to 2340 to get 2, then do it to 3400 for 3...

MichaelW

I can't follow your logic. A SHL shifts the bits of the destination operand left by the number of bit positions specified in the source operand.

1234 = 0000010011010010b
0000010011010010b SHL 1 = 0000100110100100b = 2468

Shifting a value left by n bit positions is the equivalent of multiplying the value by 2n. Shifting a value right by n bit positions is the equivalent of dividing the value by 2n.

To store the values 1,2,3,4,5,6... in the array I used:
Enter 1234
1234 / 10 = 123 remainder 4 store in element 3
123 / 10 = 12 remainder 3 store in element 2
12 / 10 = 1 remainder 2 store in element 1
1 / 10 = 0 remainder 1 store in element 0
Enter 5678
5678 / 10 = 567 remainder 8 store in element 7
...
eschew obfuscation

veronicak5678

Oh! I see what you mean. I was making a silly mistake.