forked from hcs0/Hackers-Delight
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdivluh.c.txt
88 lines (78 loc) · 2.55 KB
/
divluh.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
// Divide long unsigned by hardware "restoring" method.
// Max line length is 57, to fit in hacker.book.
#include <stdio.h>
#include <stdlib.h> // To define "exit", req'd by XLC.
// ------------------------------ cut ----------------------------------
unsigned divluh(unsigned x, unsigned y, unsigned z) {
// Divides (x || y) by z.
int i;
unsigned t;
for (i = 1; i <= 32; i++) {
t = (int)x >> 31; // All 1's if x(31) = 1.
x = (x << 1) | (y >> 31); // Shift x || y left
y = y << 1; // one bit.
if ((x | t) >= z) {
x = x - z;
y = y + 1;
}
}
return y; // Remainder is x.
}
// ------------------------------ cut ----------------------------------
// Version based on nonrestoring hardware algorithm:
// This more-or-less verifies the algorithm given in HD,
// but we don't include this C version because it's not very efficient.
unsigned divluh1(unsigned x, unsigned y, unsigned z) {
// Divides (x || y) by z.
int i;
unsigned c;
c = 0;
for (i = 1; i <= 32; i++) {
if (c == 0) {
c = x >> 31;
x = (x << 1) | (y >> 31); // Shift x || y left
y = y << 1; // one bit.
c = c ^ (x < z);
x = x - z;
}
else {
c = x >> 31;
x = (x << 1) | (y >> 31); // Shift x || y left
y = y << 1; // one bit.
x = x + z;
c = c ^ (x < z);
}
y = y + (1 - c);
}
return y; // Remainder is x.
}
int errors;
void error(unsigned x, unsigned y, unsigned z, unsigned r) {
errors = errors + 1;
printf("Error for x = %08x, y = %08x, z = %08x,"
" got %08x (%d dec)\n", x, y, z, r, r);
}
int main() {
int i, r, n;
static unsigned test[] = {0,0,1,0, 0,1,1,1, 0,21,7,3,
0,0xffffffff,1,0xffffffff, 0,0xffffffff,10,0x19999999,
1,1,2,0x80000000, 1,1,3,0x55555555, 2,4,4,0x80000001,
0x32123456,0x789abcde,0x45600000,0xb8c45446,
0x80000000,0x00000000,0x80000001,0xfffffffe,
0xfffffffe,0xffffffff,0xffffffff,0xffffffff,
0x40000000,0x00000000,0xc0000000,0x55555555,
};
n = sizeof(test)/4;
printf("divluh:\n");
for (i = 0; i < n; i += 4) {
r = divluh(test[i], test[i+1], test[i+2]);
if (r != test[i+3]) error(test[i], test[i+1], test[i+2], r);
}
printf("divluh1:\n");
for (i = 0; i < n; i += 4) {
r = divluh1(test[i], test[i+1], test[i+2]);
if (r != test[i+3]) error(test[i], test[i+1], test[i+2], r);
}
if (errors == 0)
printf("Passed all %d cases.\n", n/4);
}