home *** CD-ROM | disk | FTP | other *** search
- _OPTIMIZING INTEGER DIVISION BY A CONSTANT DIVISOR_
- by Robert Grappel
-
-
-
- [LISTING ONE]
-
- #include stdio.h
-
- /* Program to generate "star-chain-sequence" for division of an unsigned
- 16-bit integer numerator by an unsigned 16-bit integer constant denominator.
- It assumes the existence of two 32-bit integer "registers", add, subtract, and
- shift instructions. It uses the "star-chain" multiplication routine from DDJ
- #125, March 1987 page 35 */
-
- static unsigned int mult; /* global variable for trim_trailing() & binmul() */
-
- /* Support subroutine to trim trailing 0s or 1s from global variable "mult". */
- int trim_trailing(one_zero) int one_zero;
- { /* if one_zero == 0, trim trailing zeros in "mult", return "count"
- == 1, ones */
- int c; /* bit counter */
- for (c = 0; ((mult & 1) == one_zero); c++, mult >>= 1) ;
- return c;
- }
-
- /* Slightly modified version of multiplication routine */
- binmul(m) long m;
- {
- int last_shift, /* final shift count */
- last_cnt, /* count of low-order zeros */
- stkptr, /* pointer to "stack[]" */
- cnt, /* bit counter */
- ts, /* top-of-stack element */
- flag, /* flag for special-case */
- stack[16]; /* stack for shift-add/subs */
- mult = m;
- stkptr = last_cnt = 0; /* init. stack ptr. and count */
- last_shift = trim_trailing(0); /* trim trailing 0s */
- while (1)
- { /* loop to decompose "mult", building stack */
- cnt = trim_trailing(1); /* count low-order 1s */
- if (cnt > 1)
- { /* more than 1 bit, shift-subtract */
- flag = 0;
- if (last_cnt == 1)
- /* shift "k",sub,shift 1,add --> shift "k+1", sub */
- stack[stkptr-1] = -(cnt+1); /* overwrite */
- else
- stack[stkptr++] = -cnt;
- }
- else
- flag = 1; /* need another shift-add */
- if (mult == 0) break; /* decomp. "mult", now output */
- last_cnt = trim_trailing(0) + flag; /* low-order 0s */
- stack[stkptr++] = last_cnt; /* shift-add */
- }
- while (stkptr > 0)
- { /* output code from stack */
- ts = stack[--stkptr]; /* get top stack element */
- if (ts < 0)
- { /* generate shift-subtract instructions */
- printf("\nRw <<= %d",-ts);
- printf("\nRw -= R1");
- }
- else
- { /* generate shift-add instructions */
- printf("\nRw <<= %d",ts);
- printf("\nRw += R1");
- }
- }
- if (last_shift != 0) printf("\nRw <<= %d",last_shift);
- }
-
- main()
- { /* generate pseudo-instructions for star-chain division */
- int a,b,r, /* computed multiplier, addend, and remainder */
- i2, /* number of bits to scale divisor */
- denom, /* intended divisor */
- denom2; /* divisor scaled by powers-of-2 */
- int z = 65536; /* 2^16 */
- printf("\nEnter positive integer denominator: ");
- scanf("%d",&denom);
- if (denom != 0)
- { /* scale denominator by powers-of-2 */
- mult = denom;
- i2 = trim_trailing(0); /* how many powers-of-2? */
- denom2 = mult;
- if (denom2 == 1)
- { /* divisor was power-of-2, simply scale it */
- printf("\nRw = R1");
- if (i2 > 0) printf("\nRw >>= %d",i2);
- }
- else
- { /* divisor not power-of-2, scale and more */
- if (i2 > 0)
- printf("\nR1 >>= %d",i2); /* handle scaling */
- printf("\nRw = R1"); /* load work register */
- a = z / denom2; /* scaled reciprocal */
- r = z % denom2; /* remainder of recip. */
- b = a + r - 1;
- binmul(a);
- printf("\nRw += %d",b);
- printf("\nRw >>= 16");
- }
- }
- else
- printf("\nCannot divide by zero\n"); /* special case */
- }
-
-
-
- Example 1: Division by 102
-
- R1 >>= 1 scale 102 down to 51 (odd)
- Rw = R1 mult. by a = (65536/51) = 1285
- Rw <<= 2
- Rw += R1
- Rw <<= 6
- Rw += R1
- Rw <<= 2
- Rw += R1
- Rw += 1285 add b = (a + r - 1) = 1285
- Rw >>= 16 divide by z = 65536
-
-