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; |
15 | int rem, r2; |
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; |
23 | y.lo += r2 * 2 * (0x80000000 / 10); |
24 | rem += r2 * 2 * (0x80000000 % 10); |
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; |
52 | y.hi = hi; |
53 | y.lo = lo; |
54 | return y; |
55 | } |
56 | |
32874aea |
57 | uint64 uint64_add(uint64 x, uint64 y) |
58 | { |
62e3c17b |
59 | x.lo += y.lo; |
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 | { |
83 | x.lo -= y.lo; |
84 | x.hi -= y.hi + (x.lo > ~y.lo ? 1 : 0); |
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; |
97 | x.lo |= (x.hi << (32-shift)); |
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) { |
109 | x.hi <<= shift; |
110 | x.hi |= (x.lo >> (32-shift)); |
111 | x.lo <<= shift; |
112 | } else { |
113 | x.hi = x.lo << (shift-32); |
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 | } |