Related articles |
---|
integer mod with constant modulus. rocky@panix.com (R. Bernstein) (1995-06-24) |
Re: integer mod with constant modulus. mernst@theory.lcs.mit.edu (1995-06-29) |
Re: integer mod with constant modulus. markt@harlequin.co.uk (1995-07-04) |
HAKMEM #169 chase@centerline.com (1995-07-06) |
Re: HAKMEM #169 hbaker@netcom.com (1995-07-11) |
Re: HAKMEM #169 Tommy.Thorn@irisa.fr (1995-07-15) |
Newsgroups: | comp.compilers |
From: | "R. Bernstein" <rocky@panix.com> |
Keywords: | arithmetic |
Organization: | Compilers Central |
Date: | Sat, 24 Jun 1995 04:34:57 GMT |
Status: | RO |
I had an idea a long while ago about how to do possibly faster integer mod
operations for powers of 2 plus or minus 1 (e.g. 3, 7, 9, 15...).
It would be interesting to compare how this would fare with
gcc 2.6x's method for turning a constant division into a
multiplication. Its worst case too is with small moduli.
The first part of the idea is really simple and used to be taught in
school; it is known as casting out nines. Changing to a binary radix,
the rule would be: for powers of two minus 1,
you sum up blocks of bits (size = log (number+1)) in a word.
The second part of the idea comes from the beginning of an old book
``Combinatorial Algorithms,'' by Deo, Nevergelt and Reingold, but
they attribute the idea as going back to the '50s.
Blocks of bits in a word can be summed in parallel in a register using
the usual add and subtract operations provided you make sure that
there is no possibility for a carry to occur between blocks. This is
done by by copying, masking and shifting.
Putting this altogether, here's an example in C
for how x mod 7 would work where x is a 8 byte quantity.
Assume x is in register1 and also is to hold the final result.
r2 = r1;
r1 = r1 & 0xC7; /*1100 0111*/
r2 = r2 & 0x38; /*0011 1000*/
r2 = r2 >> 3;
r1 = r1 + r2;
r2 = r1;
r2 = r2 & 0xC0;
r1 = r1 & 0x3F;
r2 = r2 >> 6;
r1 = r1 + r2;
if (r1 >= 14)
r1 = r1 - 14
else if (r1 >= 7)
r1 = r1 - 7;
For mod 9 the last the r1 = r1 + r2 would be replaced by r1 = r1 - r2
and the "if" would be changed to
if (r1 < -9)
r1 = r1 + 18;
else if (r1 < 0)
r1 = r1 + 9;
Since each statement is roughly an instruction, this would map to
about 16 instructions (3 for the if). On RISC architectures where
there is often a "rotate and mask" and a three register "and"
instruction, the above instruction count would be reduced by maybe 4
instructions in the above example.
If m is log of the nearest power of two of the modulus and n the
number of bits of size of the word result, then the number of
instructions used would be 7 * (log (n - 2m) + 1);
Here, log is the base 2 truncated log. In the above case, n=8 and m=3.
So if the modulus were either 5 or 3 and the result was to be an 8-bit
word, the number of instructions would be about 21 instructions. For
a 32-bit word mod 3 (the toughest case), this would take about 35
instructions.
I often make mistakes in such computations so take the above with a
grain of salt.
--
Return to the
comp.compilers page.
Search the
comp.compilers archives again.