-
Notifications
You must be signed in to change notification settings - Fork 39
/
magicu.c.txt
102 lines (95 loc) · 3.55 KB
/
magicu.c.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Computes the magic number for unsigned division.
// Max line length is 57, to fit in hacker.book.
#include <stdlib.h>
#include <stdio.h>
// ------------------------------ 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 --------------------------------