| ??? 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 |
| Topic | Author | Date |
| 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 |



