| QUOTE |
- Any multiple of 2 (obviously) - 1000 (since it is close to 1024) and is nice for binary to decimal conversions. - 60 (close to 64) and is nice for working with degrees and minutes or seconds. |
| CODE |
| X / 5 = X/(4+1) = (X/4) /(1+1/4)= (X/4) * (1 - 1/4 + 1/16 - 1/64 + 1/256 ...) = X/4 - X/16 + X/64 - X/256 + X/1024 - X/4096 ... 1. Form y = x/4. (You shift your dividend by 2 bits to the right.) 2. Add y to sum. 2. Form z = y/4. Subtract from sum. 3. Form w = z/4. Add to sum. 4. Form v = w/4. Subtract from sum. (This is sufficient for 3DE or less.) 5. Form u = v/4. Add to sum. 6. Form t = u/4. Add to sum. 7. Form s = u/4. Add to sum. (This is sufficient for FFFF dividend.) |
| QUOTE |
If you have to divide or multiply a number by a constant there is a possibility to optimize this routine for the given constant. Multiplication and division are treated the same, because the constant can be fractional and regarded as multiplier in both cases. |
| CODE |
| 3.578(dec) = 11.1001 0011 1111 0111 1100 ...(bin) |
| CODE |
| 1111 = 10000 - 1. |
| CODE |
| 3.578(dec) = 100.0001 0100 0000 0000 0000..(bin) - 0.1000 0000 0000 0000 0100..(bin) = 4 - 1/2 + 1/16 + 1/64 - ...(dec). |
| CODE |
| 3.578 = 4 - 1/2 + 1/16 + 1/64 |
| CODE |
| rlf reg, w ;sign extension rrf reg, f |
| CODE |
-1/2 = 0 (-1+1) >> 1 = 0 -2/2 = -1 (-2+1) >>1 = -1 -3/2 = -1 (-3+1) >> 1 = -1 |
| CODE |
INPUT "enter number to divide by: ", in INPUT "bits precision: ", bits accum = -1 / in i = 1 j = 1 WHILE j < bits ni = i / 2 IF accum < 0 THEN 'neg IF ABS(accum + ni) > ABS(accum + i) THEN PRINT "Add dividend to accumulator (dividend /"; 1 / i;")" accum = accum + i END IF ELSE IF ABS(accum - ni) > ABS(accum - i) THEN PRINT "Subtract dividend from accumulator (dividend /"; 1 / i;")" accum = accum - i END IF END IF PRINT "Shift dividend right. Shift#"; j j = j + 1 i = ni WEND IF accum <> 0 THEN PRINT "Final error:"; accum; "would require 1/"; 1 / accum; "th of dividend to be added to accumulator" ELSE PRINT "no error" ENDIF |
| QUOTE |
The closest trick that I have seen for constants that are not powers of two is to multiply by 2^32/(integer constant), making sure that 2^32/(integer constant) is rounded towards infinity. |
| CODE |
| ; Edx = unsigned integer. Mov Eax,(1 Shl 31)/5+1; 2^32/10 = 2^31/5, plus 1 for rounding. Mul Edx; Multiply Edx by 1/10. ; Edx = Edx/10, rounded toward 0, Eax = destroyed. |
| QUOTE |
As another approach to this problem, you can do a "full divide" but take advantage of the fact that you know certain things about the number with which you are dividing. Just as an example, here is a MACRO I use for dividing an eight bit number by a constant {on the PIC microcontroller}: |
| CODE |
;DIVIDEL divides WREG by a literal value. ;It gives the quotient in reg and;the remainder in WREG. ;reg: the register to place the quotient ;lit: the literal with which WREG is divided ;-------------------------------------------------- DIVIDEL macro reg, lit clrf reg ;Set at zero to begin local divi, cnt divi = lit cnt = 0 while (divi & 0x80) == 0 ;Shift literal until MSB is in bit 7 divi <<= 1 cnt++ ;Keep up with number of shifts endw while cnt >= 0 addlw 0 - divi ;Subtract shifted literal btfsc STATUS, C ;If positive then bsf reg, cnt ; set appropriate bit (i.e. divides once) btfss STATUS, C ;else addlw divi ; add back to restore number divi >>= 1 ;shift literal and continue until done cnt-- endw endm |
| CODE |
For Y = X/10: Y = (X + X/2 + X/8 - X/64) / 16 |