You can use the fact that (N-1)% N == -1.
Thus, (65536 * a)% 65537 == -a% 65537.
Also, -a% 65537 == -a + 1 (mod 65536) when 0 is interpreted as 65536
uint16_t fastmod65537(uint16_t a, uint16_t b) { uint32_t c; uint16_t hi, lo; if (a == 0) return -b + 1; if (b == 0) return -a + 1; c = (uint32_t)a * (uint32_t)b; hi = c >> 16; lo = c; if (lo > hi) return lo-hi; return lo-hi+1; }
The only problem here is that if hi == lo , the result will be 0. Fortunately, the test suite confirms that it really cannot be ...
int main() { uint64_t a, b; for (a = 1; a <= 65536; a++) for (b = 1; b <= 65536; b++) { uint64_t c = a*b; uint32_t d = (c % 65537) & 65535; uint32_t e = m(a & 65535, b & 65535); if (d != e) printf("a * b % 65537 != m(%d, %d) real=%dm()=%d\n", (uint32_t)a, (uint32_t)b, d, e); } }
Output: none
source share