These two methods are not related to each other. The bitwise method is apparently associated with some methods of efficiently calculating modulo b-1 using the digital base b , known in decimal arithmetic as "expelling nines . "
The method based on multiplication is directly based on the definition of division when it is performed by multiplication by the inverse. Denoting / mathematical division, we have
int_quot = (int)(i / 3) frac_quot = i / 3 - int_quot = i / 3 - (int)(i / 3) i % 3 = 3 * frac_quot = 3 * (i / 3 - (int)(i / 3))
The fractional part of the mathematical factor is converted directly to the remainder of integer division: if the fraction is 0, the remainder is 0, if the fraction is 1/3, the remainder is 1, if the fraction is 2/3, the remainder is 2. This means that we only need to study fractional part of the private.
Instead of dividing by 3, we can multiply by 1/3. If we perform the calculation in 32.32 with a fixed point, 1/3 corresponds to 2 32 * 1/3, which is a number between 0x55555555 and 0x55555556 . For reasons that will become obvious in the near future, we use revaluation here, that is, the result of rounding 0x555555556 .
When we multiply 0x55555556 by i , the most significant 32 bits of the full 64-bit product will contain the integral part of the quotient (int)(i * 1/3) = (int)(i / 3) . We are not interested in this integral part, so we do not calculate and store it. The lower 32 bits of the product are one of the fractions 0/3, 1/3, 2/3, however, they are calculated with a small error, since our value 0x555555556 slightly larger than 1/3:
i = 1: i * 0.55555556 = 0.555555556 i = 2: i * 0.55555556 = 0.AAAAAAAAC i = 3: i * 0.55555556 = 1.000000002 i = 4: i * 0.55555556 = 1.555555558 i = 5: i * 0.55555556 = 1.AAAAAAAAE
If we look at the most significant bits of the three possible fraction values ββin binary format, we find 0x5 = 0101 , 0xA = 1010 , 0x0 = 0000 . Thus, the two most significant bits of the fractional part of the factor exactly correspond to the desired modulo values. Since we are dealing with 32-bit operands, we can extract these two bits with a right shift of 30 bits, followed by a 0x3 mask to isolate the two bits. I think masking is necessary in Java, since 32-bit integers are always signed. For uint32_t operands in C / C ++, one shift is enough.
Now we see why the choice is 0x55555555 , since 1/3 view will not work. The fractional part of the factor would turn into 0xFFFFFFF* , and since 0xF = 1111 in binary terms, modular calculation will return an incorrect result of 3.
Note that as i increases, the accumulated error from the inaccurate 1/3 representation affects more and more bits of the fractional part. In fact, exhaustive testing shows that the method only works for i < 0x60000000 : beyond this limit, the error overflows the most significant bit bits that represent our result.