1 /*-------------------------------------------------------------------------
2 *
3 * testint128.c
4 * Testbed for roll-our-own 128-bit integer arithmetic.
5 *
6 * This is a standalone test program that compares the behavior of an
7 * implementation in int128.h to an (assumed correct) int128 native type.
8 *
9 * Copyright (c) 2017, PostgreSQL Global Development Group
10 *
11 *
12 * IDENTIFICATION
13 * src/tools/testint128.c
14 *
15 *-------------------------------------------------------------------------
16 */
17
18 #include "postgres_fe.h"
19
20 /*
21 * By default, we test the non-native implementation in int128.h; but
22 * by predefining USE_NATIVE_INT128 to 1, you can test the native
23 * implementation, just to be sure.
24 */
25 #ifndef USE_NATIVE_INT128
26 #define USE_NATIVE_INT128 0
27 #endif
28
29 #include "common/int128.h"
30
31 /*
32 * We assume the parts of this union are laid out compatibly.
33 */
34 typedef union
35 {
36 int128 i128;
37 INT128 I128;
38 union
39 {
40 #ifdef WORDS_BIGENDIAN
41 int64 hi;
42 uint64 lo;
43 #else
44 uint64 lo;
45 int64 hi;
46 #endif
47 } hl;
48 } test128;
49
50
51 /*
52 * Control version of comparator.
53 */
54 static inline int
my_int128_compare(int128 x,int128 y)55 my_int128_compare(int128 x, int128 y)
56 {
57 if (x < y)
58 return -1;
59 if (x > y)
60 return 1;
61 return 0;
62 }
63
64 /*
65 * Get a random uint64 value.
66 * We don't assume random() is good for more than 16 bits.
67 */
68 static uint64
get_random_uint64(void)69 get_random_uint64(void)
70 {
71 uint64 x;
72
73 x = (uint64) (random() & 0xFFFF) << 48;
74 x |= (uint64) (random() & 0xFFFF) << 32;
75 x |= (uint64) (random() & 0xFFFF) << 16;
76 x |= (uint64) (random() & 0xFFFF);
77 return x;
78 }
79
80 /*
81 * Main program.
82 *
83 * Generates a lot of random numbers and tests the implementation for each.
84 * The results should be reproducible, since we don't call srandom().
85 *
86 * You can give a loop count if you don't like the default 1B iterations.
87 */
88 int
main(int argc,char ** argv)89 main(int argc, char **argv)
90 {
91 long count;
92
93 if (argc >= 2)
94 count = strtol(argv[1], NULL, 0);
95 else
96 count = 1000000000;
97
98 while (count-- > 0)
99 {
100 int64 x = get_random_uint64();
101 int64 y = get_random_uint64();
102 int64 z = get_random_uint64();
103 test128 t1;
104 test128 t2;
105
106 /* check unsigned addition */
107 t1.hl.hi = x;
108 t1.hl.lo = y;
109 t2 = t1;
110 t1.i128 += (int128) (uint64) z;
111 int128_add_uint64(&t2.I128, (uint64) z);
112
113 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
114 {
115 printf("%016lX%016lX + unsigned %lX\n", x, y, z);
116 printf("native = %016lX%016lX\n", t1.hl.hi, t1.hl.lo);
117 printf("result = %016lX%016lX\n", t2.hl.hi, t2.hl.lo);
118 return 1;
119 }
120
121 /* check signed addition */
122 t1.hl.hi = x;
123 t1.hl.lo = y;
124 t2 = t1;
125 t1.i128 += (int128) z;
126 int128_add_int64(&t2.I128, z);
127
128 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
129 {
130 printf("%016lX%016lX + signed %lX\n", x, y, z);
131 printf("native = %016lX%016lX\n", t1.hl.hi, t1.hl.lo);
132 printf("result = %016lX%016lX\n", t2.hl.hi, t2.hl.lo);
133 return 1;
134 }
135
136 /* check multiplication */
137 t1.i128 = (int128) x * (int128) y;
138
139 t2.hl.hi = t2.hl.lo = 0;
140 int128_add_int64_mul_int64(&t2.I128, x, y);
141
142 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
143 {
144 printf("%lX * %lX\n", x, y);
145 printf("native = %016lX%016lX\n", t1.hl.hi, t1.hl.lo);
146 printf("result = %016lX%016lX\n", t2.hl.hi, t2.hl.lo);
147 return 1;
148 }
149
150 /* check comparison */
151 t1.hl.hi = x;
152 t1.hl.lo = y;
153 t2.hl.hi = z;
154 t2.hl.lo = get_random_uint64();
155
156 if (my_int128_compare(t1.i128, t2.i128) !=
157 int128_compare(t1.I128, t2.I128))
158 {
159 printf("comparison failure: %d vs %d\n",
160 my_int128_compare(t1.i128, t2.i128),
161 int128_compare(t1.I128, t2.I128));
162 printf("arg1 = %016lX%016lX\n", t1.hl.hi, t1.hl.lo);
163 printf("arg2 = %016lX%016lX\n", t2.hl.hi, t2.hl.lo);
164 return 1;
165 }
166
167 /* check case with identical hi parts; above will hardly ever hit it */
168 t2.hl.hi = x;
169
170 if (my_int128_compare(t1.i128, t2.i128) !=
171 int128_compare(t1.I128, t2.I128))
172 {
173 printf("comparison failure: %d vs %d\n",
174 my_int128_compare(t1.i128, t2.i128),
175 int128_compare(t1.I128, t2.I128));
176 printf("arg1 = %016lX%016lX\n", t1.hl.hi, t1.hl.lo);
177 printf("arg2 = %016lX%016lX\n", t2.hl.hi, t2.hl.lo);
178 return 1;
179 }
180 }
181
182 return 0;
183 }
184