// Computes the magic number for unsigned division. // Max line length is 57, to fit in hacker.book. #include #include // ------------------------------ cut ---------------------------------- struct mu {unsigned M; // Magic number, int a; // "add" indicator, int s;}; // and shift amount. // ---------------------------- end cut -------------------------------- int main() { struct mu magicu(unsigned); struct mu magicu2(unsigned); struct mu mag; mag = magicu(3); printf("M = %08x a = %d s = %d\n", mag.M, mag.a, mag.s); if (mag.M + mag.a + mag.s != 0xAAAAAAAB + 0 + 1) return 1; mag = magicu(7); printf("M = %08x a = %d s = %d\n", mag.M, mag.a, mag.s); if (mag.M + mag.a + mag.s != 0x24924925 + 1 + 3) return 2; mag = magicu2(3); printf("M = %08x a = %d s = %d\n", mag.M, mag.a, mag.s); if (mag.M + mag.a + mag.s != 0xAAAAAAAB + 0 + 1) return 11; mag = magicu2(7); printf("M = %08x a = %d s = %d\n", mag.M, mag.a, mag.s); if (mag.M + mag.a + mag.s != 0x24924925 + 1 + 3) return 12; return 0; } // ------------------------------ cut ---------------------------------- struct mu magicu(unsigned d) { // Must have 1 <= d <= 2**32-1. int p; unsigned nc, delta, q1, r1, q2, r2; struct mu magu; magu.a = 0; // Initialize "add" indicator. nc = -1 - (-d)%d; // Unsigned arithmetic here. p = 31; // Init. p. q1 = 0x80000000/nc; // Init. q1 = 2**p/nc. r1 = 0x80000000 - q1*nc;// Init. r1 = rem(2**p, nc). q2 = 0x7FFFFFFF/d; // Init. q2 = (2**p - 1)/d. r2 = 0x7FFFFFFF - q2*d; // Init. r2 = rem(2**p - 1, d). do { p = p + 1; if (r1 >= nc - r1) { q1 = 2*q1 + 1; // Update q1. r1 = 2*r1 - nc;} // Update r1. else { q1 = 2*q1; r1 = 2*r1;} if (r2 + 1 >= d - r2) { if (q2 >= 0x7FFFFFFF) magu.a = 1; q2 = 2*q2 + 1; // Update q2. r2 = 2*r2 + 1 - d;} // Update r2. else { if (q2 >= 0x80000000) magu.a = 1; q2 = 2*q2; r2 = 2*r2 + 1;} delta = d - 1 - r2; } while (p < 64 && (q1 < delta || (q1 == delta && r1 == 0))); magu.M = q2 + 1; // Magic number magu.s = p - 32; // and shift amount to return return magu; // (magu.a was set above). } // ---------------------------- end cut -------------------------------- // ------------------------------ cut ---------------------------------- struct mu magicu2(unsigned d) { // Must have 1 <= d <= 2**32-1. int p; unsigned p32, q, r, delta; struct mu magu; magu.a = 0; // Initialize "add" indicator. p = 31; // Initialize p. q = 0x7FFFFFFF/d; // Initialize q = (2**p - 1)/d. r = 0x7FFFFFFF - q*d; // Init. r = rem(2**p - 1, d). do { p = p + 1; if (p == 32) p32 = 1; // Set p32 = 2**(p-32). else p32 = 2*p32; if (r + 1 >= d - r) { if (q >= 0x7FFFFFFF) magu.a = 1; q = 2*q + 1; // Update q. r = 2*r + 1 - d; // Update r. } else { if (q >= 0x80000000) magu.a = 1; q = 2*q; r = 2*r + 1; } delta = d - 1 - r; } while (p < 64 && p32 < delta); magu.M = q + 1; // Magic number and magu.s = p - 32; // shift amount to return return magu; // (magu.a was set above). } // ---------------------------- end cut --------------------------------