问题
I want to find a way to know if an integer is divided by 3 or 7 without using division, because it is very slow in MIPS assembly.
I have done a lot of research but found nothing.
回答1:
There's a method described by Granlund & Montgomery that requires the modular / multiplicative inverse of the (odd) divisor modulo 2**b
. (Some parts of this paper have been improved recently)
The divisors: (d) = 3, 7
(odd numbers) are an easy case. Assuming 32 bit (unsigned) arithmetic, the inverses modulo 2**32
yield 2863311531 (0xAAAAAAAB)
and 3067833783 (0xB6DB6DB7)
respectively. There's an online calculator here.
We also need the qmax = (2**32 - 1) / d
values: 0x55555555
and 0x24924924
resp.
To test a 32 bit (unsigned) number (n)
, perform a single word multiply - that is, discard the high word of the full 64 bit result: q = dinv * n
If (n)
is divisible by (d)
, then (q)
must satisfy: q * d == n
and q <= qmax
. e.g.,
int is_divisible_by_3 (uint32_t n)
{
uint32_t q = n * 0xAAAAAAAB;
return (q <= 0x55555555 && (q * 3 == n))
}
Which replaces a division / remainder with a couple of single word multiplications.
And similarly for d = 7
. Alternatively, a modern compiler like gcc will perform a similar optimization for a constant divisor / modulus, e.g., if (n % 3 == 0) ...
- in the assembly generated for MIPS, etc.
回答2:
You can sum the remainders for the individual bits. The 2^n mod 3
goes like 1,2,1,2,...
and 2^n mod 7
goes like 1,2,4,1,2,4,...
.
Use a lookup table to make it even faster.
来源:https://stackoverflow.com/questions/22186509/how-to-find-remainder-without-division-or-modulo-operator-in-mips-assembly