Email: Password: Remember Me | Create Account (Free)

Back to Subject List

Old thread has been locked -- no new posts accepted in this thread
???
11/29/02 14:40
Read: times


 
#33446 - RE: Division by 32 bits
;I forgot where i found this code.
;Maybe from here...
;It works well.
;

$DEBUG

LONG_DIVISION SEGMENT CODE

EXTRN DATA(NUMERATOR, DENOMINATOR, QUOTIENT)
EXTRN NUMBER(NUMERATOR_BYTES, QUOTIENT_BYTES)
PUBLIC LONG_DIVIDE, TIMES_TWO_AND_COMPARE

RSEG LONG_DIVISION

BYTE_COUNT EQU R2
BIT_COUNT EQU R3
HIGHEST_NUMERATOR_BYTE EQU R4
HIGHEST_DENOMINATOR_BYTE EQU R5


;******************************************************************************
;
; LONG_DIVIDE
;
; NUMERATOR
; CALCULATES QUOTIENT = -----------
; DENOMINATOR
;
; NUMERATOR and DENOMINATOR are N-byte unsigned integers.
;
; Requirements: 1. The most significant bit of DENOMINATOR must = 0
; 2. NUMERATOR must be < DENOMINATOR
;
; QUOTIENT is m bits long and of the form:
;
; QUOTIENT = 0. q1 q2 q3 ... qm
;
; where qn is the coefficient of 2**(-n).
;
;
; INPUTS: NUMERATOR N bytes in externally defined DATA
; (LSByte at NUMERATOR, next byte in NUMERATOR+1, etc.)
;
; DENOMINATOR N bytes in externally defined DATA
;
; NUMERATOR_BYTES externally defined numerical constant
; = N, number of bytes in NUMERATOR and DENOMINATOR
;
; QUOTIENT_BYTES externally defined numerical constant
; = M, number of bytes in QUOTIENT
;
;
; OUTPUTS: QUOTIENT M bytes in externally defined DATA
;
;
; ENTRY POINTS: LONG_DIVIDE (primary)
; TIMES_TWO_AND_COMPARE (special purpose)
;
; VARIABLES AND REGISTERS MODIFIED:
;
; NUMERATOR (all N bytes of it)
; QUOTIENT (all M bytes of it)
; ACC, B, PSW, R0, R1, R2, R3, R4, R5
;
; ERROR EXIT: Exit with OV = 1 indicates either/or
;
; 1. Most significant bit of denominator not 0
; 2. NUMERATOR >= DENOMINATOR
; 3. Too many bits in quotient (max is 255)
;
;
; An example of how to use this routine:
;
; Suppose you want to divide a 5-byte integer
;
; N4 N3 N2 N1 N0
;
; by a 3-byte integer
;
; D2 D1 D0.
;
;
; If D2 > 0, the quotient will have at most 3 integer bytes, but can have any
; number of bytes to the right of the decimal point. If we calculate the
; quotient to 3 bytes, then we'll have the integer part of it. If we calculate
; the quotient to 10 bytes, then we'll have the integer part and 7 bytes to the
; right of the decimal point. For this example, we'll calculate the quotient
; to 4 bytes, so the quotient will be of the form
;
;
; Q3 Q2 Q1 . Q0
;
; To satisfy the requirements that
;
; 1. Most significant bit of denominator = 0
; 2. NUMERATOR < DENOMINATOR
;
; set the problem up this way:
;
; N4 N3 N2 N1 N0 00 00 N4 N3 N2 N1 N0
; -------------- = -------------------- x 1000000H
; D2 D1 D0 00 D2 D1 D0 00 00 00
;
; Note that requirement #2 requires also that D2 > 0.
;
; The LONG_DIVIDE routine will calculate
;
; 00 00 N4 N3 N2 N1 N0
; -------------------- = 0. Q3 Q2 Q1 Q0
; 00 D2 D1 D0 00 00 00
;
; The calling program must then multiply this result by 1000000H, which in
; fact involves only redefining where the decimal point is:
;
; 0. Q3 Q2 Q1 Q0 x 1000000H = Q3 Q2 Q1 . Q0
;
; The calling program must define an DATA segment having
;
; NUMERATOR DS 7
; DENOMINATOR DS 7
; QUOTIENT DS 4
;
; The calling program must also define the numerical constants
;
; NUMERATOR_BYTES EQU 7
; QUOTIENT_BYTES EQU 4
;
; These parameters must be declared PUBLIC:
;
; PUBLIC NUMERATOR, DENOMINATOR, QUOTIENT, NUMERATOR_BYTES, QUOTIENT_BYTES
;
; Software in the calling program loads NUMERATOR with 00 00 N4 N3 N2 N1 N0,
; and DENOMINATOR with 00 D2 D1 D0 00 00 00. It is verified that D2 > 0.
; Then CALL LONG_DIVIDE. The divide routine leaves QUOTIENT holding the
; result. It leaves the content of DENOMINATOR unchanged, but changes the
; content of NUMERATOR. Therefore if you want to use the original value of
; NUMERATOR in subsequent calculations, you'll need to save it elsewhere.
;
; QUOTIENT can be rounded off to the nearest LSBit by calculating what the
; (m+1)th bit would be and incrementing QUOTIENT if q(m+1) = 1.
;
; The code for that would be:
;
; CALL LONG_DIVIDE ;CALCULATES QUOTIENT
; CALL TIMES_TWO_AND_COMPARE ;CALCULATES q(m+1)
; JNC OVER
; MOV R0,#QUOTIENT-1
; MOV R1,#QUOTIENT_BYTES
; SETB C
; INCREMENT_LOOP:
; INC R0
; MOV A,@R0
; ADDC A,#0
; MOV @R0,A
; DJNZ R1,INCREMENT_LOOP
; OVER: (continue)
;
;
;
; The algorithm used by the subroutine is:
;
; p(0) = NUMERATOR
; 2 x p(n-1) = qn x DEMOMINATOR + p(n), for n = 1,2,...m.
;
; The procedure is first to calculate 2 x p(n-1), then compare it with
; DENOMINATOR.
;
; If 2 x p(n-1) >= DENOMINATOR, then qn = 1
; If 2 x p(n-1) < DENOMINATOR, then qn = 0
;
; The routine calculates the m bits in QUOTIENT. The remainder is
; 2**(-m) x p(m). The routine leaves p(m) in the N bytes that
; NUMERATOR was in.
;
;******************************************************************************



LONG_DIVIDE:
MOV A,#NUMERATOR
ADD A,#NUMERATOR_BYTES
DEC A
MOV HIGHEST_NUMERATOR_BYTE,A
MOV A,#DENOMINATOR
ADD A,#NUMERATOR_BYTES
DEC A
MOV HIGHEST_DENOMINATOR_BYTE,A
MOV A,#QUOTIENT_BYTES
MOV B,#8
MUL AB
JNB OV,$+4
RET
MOV BIT_COUNT,A ;ESTABLISH NUMBER OF BITS IN QUOTIENT

ALGORITHM:
CALL TIMES_TWO_AND_COMPARE

; NUMERATOR = 2 X NUMERATOR
; Then, if NUMERATOR < DENOMINATOR then qn = 0
; if NUMERATOR >= DENOMINATOR then qn = 1

; TIMES_TWO_AND_COMPARE LEAVES qn IN CY

MOV F0,C ;TEMP SAVE qn IN F0

; SHIFT qn INTO QUOTIENT:

MOV BYTE_COUNT,#QUOTIENT_BYTES
MOV R0,#QUOTIENT
Q_SHIFT:
MOV A,@R0
RLC A
MOV @R0,A
INC R0
DJNZ BYTE_COUNT,Q_SHIFT

; CALCULATE p(n) = NUMERATOR IF qn = 0
; = NUMERATOR - DENOMINATOR IF qn = 1

JNB F0,BIT_COUNT_TEST
MOV R0,#NUMERATOR
MOV R1,#DENOMINATOR
MOV BYTE_COUNT,#NUMERATOR_BYTES
CLR C
SUBTRACT:
MOV A,@R0
SUBB A,@R1
MOV @R0,A
INC R0
INC R1
DJNZ BYTE_COUNT,SUBTRACT
BIT_COUNT_TEST:
DJNZ BIT_COUNT,ALGORITHM
CLR OV
RET


TIMES_TWO_AND_COMPARE:
MOV BYTE_COUNT,#NUMERATOR_BYTES
MOV R0,#NUMERATOR
CLR C

LEFT_SHIFT:
MOV A,@R0
RLC A
MOV @R0,A
INC R0
DJNZ BYTE_COUNT,LEFT_SHIFT
JC ERROR ;CY = 1 AFTER TIMES_TWO INDICATES OVERFLOW

MOV A,HIGHEST_NUMERATOR_BYTE
MOV R0,A
MOV A,HIGHEST_DENOMINATOR_BYTE
MOV R1,A
MOV BYTE_COUNT,#NUMERATOR_BYTES

COMPARISON:
MOV A,@R0
MOV B,@R1
CJNE A,B,DONE ;SETS CY IF NUMERATOR < DENOMINATOR
;CLEARS CY IF NUMERATOR >= DENOMINATOR
DEC R0
DEC R1
DJNZ BYTE_COUNT,COMPARISON

DONE: CPL C ;CLEARS CY IF NUMERATOR < DENOMINATOR
;SETS CY IF NUMERATOR >= DENOMINATOR
RET ;THUS CY = qn

ERROR: SETB OV
POP ACC
POP ACC
RET
END


List of 6 messages in thread
TopicAuthorDate
Division by 32 bits            01/01/70 00:00      
RE: Division by 32 bits            01/01/70 00:00      
RE: Division by 32 bits            01/01/70 00:00      
RE: Division by 32 bits            01/01/70 00:00      
RE: Division by 32 bits            01/01/70 00:00      
RE: Division by 32 bits            01/01/70 00:00      

Back to Subject List