62e3c17b |
1 | /* |
2 | * Handling of the int64 and uint64 types. Done in 32-bit integers, |
3 | * for (pre-C99) portability. Hopefully once C99 becomes widespread |
4 | * we can kiss this lot goodbye... |
5 | */ |
6 | |
7 | #include <assert.h> |
d92624dc |
8 | #include <string.h> |
62e3c17b |
9 | |
d92624dc |
10 | #include "int64.h" |
62e3c17b |
11 | |
32874aea |
12 | uint64 uint64_div10(uint64 x, int *remainder) |
13 | { |
62e3c17b |
14 | uint64 y; |
68fdd3ee |
15 | unsigned int rem, r2; |
62e3c17b |
16 | y.hi = x.hi / 10; |
17 | y.lo = x.lo / 10; |
18 | rem = x.lo % 10; |
19 | /* |
20 | * Now we have to add in the remainder left over from x.hi. |
21 | */ |
22 | r2 = x.hi % 10; |
68fdd3ee |
23 | y.lo += r2 * 429496729; |
24 | rem += r2 * 6; |
62e3c17b |
25 | y.lo += rem / 10; |
26 | rem %= 10; |
27 | |
28 | if (remainder) |
29 | *remainder = rem; |
30 | return y; |
31 | } |
32 | |
32874aea |
33 | void uint64_decimal(uint64 x, char *buffer) |
34 | { |
62e3c17b |
35 | char buf[20]; |
36 | int start = 20; |
37 | int d; |
38 | |
70637309 |
39 | do { |
62e3c17b |
40 | x = uint64_div10(x, &d); |
41 | assert(start > 0); |
42 | buf[--start] = d + '0'; |
70637309 |
43 | } while (x.hi || x.lo); |
62e3c17b |
44 | |
32874aea |
45 | memcpy(buffer, buf + start, sizeof(buf) - start); |
46 | buffer[sizeof(buf) - start] = '\0'; |
62e3c17b |
47 | } |
48 | |
32874aea |
49 | uint64 uint64_make(unsigned long hi, unsigned long lo) |
50 | { |
62e3c17b |
51 | uint64 y; |
ccc19097 |
52 | y.hi = hi & 0xFFFFFFFFU; |
68fdd3ee |
53 | y.lo = lo & 0xFFFFFFFFU; |
62e3c17b |
54 | return y; |
55 | } |
56 | |
32874aea |
57 | uint64 uint64_add(uint64 x, uint64 y) |
58 | { |
68fdd3ee |
59 | x.lo = (x.lo + y.lo) & 0xFFFFFFFFU; |
62e3c17b |
60 | x.hi += y.hi + (x.lo < y.lo ? 1 : 0); |
61 | return x; |
62 | } |
63 | |
32874aea |
64 | uint64 uint64_add32(uint64 x, unsigned long y) |
65 | { |
62e3c17b |
66 | uint64 yy; |
67 | yy.hi = 0; |
68 | yy.lo = y; |
69 | return uint64_add(x, yy); |
70 | } |
d92624dc |
71 | |
72 | int uint64_compare(uint64 x, uint64 y) |
73 | { |
74 | if (x.hi != y.hi) |
75 | return x.hi < y.hi ? -1 : +1; |
76 | if (x.lo != y.lo) |
77 | return x.lo < y.lo ? -1 : +1; |
78 | return 0; |
79 | } |
c55cfdec |
80 | |
81 | uint64 uint64_subtract(uint64 x, uint64 y) |
82 | { |
68fdd3ee |
83 | x.lo = (x.lo - y.lo) & 0xFFFFFFFFU; |
84 | x.hi = (x.hi - y.hi - (x.lo > (y.lo ^ 0xFFFFFFFFU) ? 1 : 0)) & 0xFFFFFFFFU; |
c55cfdec |
85 | return x; |
86 | } |
87 | |
88 | double uint64_to_double(uint64 x) |
89 | { |
90 | return (4294967296.0 * x.hi) + (double)x.lo; |
91 | } |
92 | |
93 | uint64 uint64_shift_right(uint64 x, int shift) |
94 | { |
95 | if (shift < 32) { |
96 | x.lo >>= shift; |
68fdd3ee |
97 | x.lo |= (x.hi << (32-shift)) & 0xFFFFFFFFU; |
c55cfdec |
98 | x.hi >>= shift; |
99 | } else { |
100 | x.lo = x.hi >> (shift-32); |
101 | x.hi = 0; |
102 | } |
103 | return x; |
104 | } |
105 | |
106 | uint64 uint64_shift_left(uint64 x, int shift) |
107 | { |
108 | if (shift < 32) { |
68fdd3ee |
109 | x.hi = (x.hi << shift) & 0xFFFFFFFFU; |
c55cfdec |
110 | x.hi |= (x.lo >> (32-shift)); |
68fdd3ee |
111 | x.lo = (x.lo << shift) & 0xFFFFFFFFU; |
c55cfdec |
112 | } else { |
68fdd3ee |
113 | x.hi = (x.lo << (shift-32)) & 0xFFFFFFFFU; |
c55cfdec |
114 | x.lo = 0; |
115 | } |
116 | return x; |
117 | } |
118 | |
119 | uint64 uint64_from_decimal(char *str) |
120 | { |
121 | uint64 ret; |
122 | ret.hi = ret.lo = 0; |
123 | while (*str >= '0' && *str <= '9') { |
124 | ret = uint64_add(uint64_shift_left(ret, 3), |
125 | uint64_shift_left(ret, 1)); |
126 | ret = uint64_add32(ret, *str - '0'); |
127 | str++; |
128 | } |
129 | return ret; |
130 | } |
68fdd3ee |
131 | |
132 | #ifdef TESTMODE |
133 | |
134 | #include <stdio.h> |
135 | |
136 | int main(void) |
137 | { |
138 | uint64 x, y, z; |
139 | char buf[80]; |
140 | |
141 | x = uint64_make(0x3456789AUL, 0xDEF01234UL); |
142 | printf("%08lx.%08lx\n", x.hi, x.lo); |
143 | uint64_decimal(x, buf); |
144 | printf("%s\n", buf); |
145 | |
146 | y = uint64_add32(x, 0xFFFFFFFFU); |
147 | printf("%08lx.%08lx\n", y.hi, y.lo); |
148 | uint64_decimal(y, buf); |
149 | printf("%s\n", buf); |
150 | |
151 | z = uint64_subtract(y, x); |
152 | printf("%08lx.%08lx\n", z.hi, z.lo); |
153 | uint64_decimal(z, buf); |
154 | printf("%s\n", buf); |
155 | |
156 | z = uint64_subtract(x, y); |
157 | printf("%08lx.%08lx\n", z.hi, z.lo); |
158 | uint64_decimal(z, buf); |
159 | printf("%s\n", buf); |
160 | |
161 | y = uint64_shift_right(x, 4); |
162 | printf("%08lx.%08lx\n", y.hi, y.lo); |
163 | |
164 | y = uint64_shift_right(x, 36); |
165 | printf("%08lx.%08lx\n", y.hi, y.lo); |
166 | |
167 | y = uint64_shift_left(x, 4); |
168 | printf("%08lx.%08lx\n", x.hi, x.lo); |
169 | |
170 | y = uint64_shift_left(x, 36); |
171 | printf("%08lx.%08lx\n", x.hi, x.lo); |
172 | |
173 | return 0; |
174 | } |
175 | #endif |