PostgreSQL Source Code git master
test_int128.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * test_int128.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-2025, PostgreSQL Global Development Group
10 *
11 *
12 * IDENTIFICATION
13 * src/test/modules/test_int128/test_int128.c
14 *
15 *-------------------------------------------------------------------------
16 */
17
18#include "postgres_fe.h"
19
20#include <time.h>
21
22/* Require a native int128 type */
23#ifdef HAVE_INT128
24
25/*
26 * By default, we test the non-native implementation in int128.h; but
27 * by predefining USE_NATIVE_INT128 to 1, you can test the native
28 * implementation, just to be sure.
29 */
30#ifndef USE_NATIVE_INT128
31#define USE_NATIVE_INT128 0
32#endif
33
34#include "common/int128.h"
35#include "common/pg_prng.h"
36
37/*
38 * We assume the parts of this union are laid out compatibly.
39 */
40typedef union
41{
42 int128 i128;
43 INT128 I128;
44 struct
45 {
46#ifdef WORDS_BIGENDIAN
47 int64 hi;
48 uint64 lo;
49#else
50 uint64 lo;
51 int64 hi;
52#endif
53 } hl;
54} test128;
55
56#define INT128_HEX_FORMAT "%016" PRIx64 "%016" PRIx64
57
58/*
59 * Control version of comparator.
60 */
61static inline int
62my_int128_compare(int128 x, int128 y)
63{
64 if (x < y)
65 return -1;
66 if (x > y)
67 return 1;
68 return 0;
69}
70
71/*
72 * Main program.
73 *
74 * Generates a lot of random numbers and tests the implementation for each.
75 * The results should be reproducible, since we use a fixed PRNG seed.
76 *
77 * You can give a loop count if you don't like the default 1B iterations.
78 */
79int
80main(int argc, char **argv)
81{
82 long count;
83
85
86 if (argc >= 2)
87 count = strtol(argv[1], NULL, 0);
88 else
89 count = 1000000000;
90
91 while (count-- > 0)
92 {
98 test128 t1;
99 test128 t2;
100 test128 t3;
101 int32 r1;
102 int32 r2;
103
104 /* prevent division by zero in the 128/32-bit division test */
105 while (z32 == 0)
107
108 /* check unsigned addition */
109 t1.hl.hi = x;
110 t1.hl.lo = y;
111 t2 = t1;
112 t1.i128 += (int128) (uint64) z;
113 int128_add_uint64(&t2.I128, (uint64) z);
114
115 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
116 {
117 printf(INT128_HEX_FORMAT " + unsigned %016" PRIx64 "\n", x, y, z);
118 printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
119 printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
120 return 1;
121 }
122
123 /* check signed addition */
124 t1.hl.hi = x;
125 t1.hl.lo = y;
126 t2 = t1;
127 t1.i128 += (int128) z;
128 int128_add_int64(&t2.I128, z);
129
130 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
131 {
132 printf(INT128_HEX_FORMAT " + signed %016" PRIx64 "\n", x, y, z);
133 printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
134 printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
135 return 1;
136 }
137
138 /* check 128-bit signed addition */
139 t1.hl.hi = x;
140 t1.hl.lo = y;
141 t2 = t1;
142 t3.hl.hi = z;
143 t3.hl.lo = w;
144 t1.i128 += t3.i128;
145 int128_add_int128(&t2.I128, t3.I128);
146
147 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
148 {
149 printf(INT128_HEX_FORMAT " + " INT128_HEX_FORMAT "\n", x, y, z, w);
150 printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
151 printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
152 return 1;
153 }
154
155 /* check unsigned subtraction */
156 t1.hl.hi = x;
157 t1.hl.lo = y;
158 t2 = t1;
159 t1.i128 -= (int128) (uint64) z;
160 int128_sub_uint64(&t2.I128, (uint64) z);
161
162 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
163 {
164 printf(INT128_HEX_FORMAT " - unsigned %016" PRIx64 "\n", x, y, z);
165 printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
166 printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
167 return 1;
168 }
169
170 /* check signed subtraction */
171 t1.hl.hi = x;
172 t1.hl.lo = y;
173 t2 = t1;
174 t1.i128 -= (int128) z;
175 int128_sub_int64(&t2.I128, z);
176
177 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
178 {
179 printf(INT128_HEX_FORMAT " - signed %016" PRIx64 "\n", x, y, z);
180 printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
181 printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
182 return 1;
183 }
184
185 /* check 64x64-bit multiply-add */
186 t1.hl.hi = x;
187 t1.hl.lo = y;
188 t2 = t1;
189 t1.i128 += (int128) z * (int128) w;
190 int128_add_int64_mul_int64(&t2.I128, z, w);
191
192 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
193 {
194 printf(INT128_HEX_FORMAT " + %016" PRIx64 " * %016" PRIx64 "\n", x, y, z, w);
195 printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
196 printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
197 return 1;
198 }
199
200 /* check 64x64-bit multiply-subtract */
201 t1.hl.hi = x;
202 t1.hl.lo = y;
203 t2 = t1;
204 t1.i128 -= (int128) z * (int128) w;
205 int128_sub_int64_mul_int64(&t2.I128, z, w);
206
207 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
208 {
209 printf(INT128_HEX_FORMAT " - %016" PRIx64 " * %016" PRIx64 "\n", x, y, z, w);
210 printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
211 printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
212 return 1;
213 }
214
215 /* check 128/32-bit division */
216 t3.hl.hi = x;
217 t3.hl.lo = y;
218 t1.i128 = t3.i128 / z32;
219 r1 = (int32) (t3.i128 % z32);
220 t2 = t3;
221 int128_div_mod_int32(&t2.I128, z32, &r2);
222
223 if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
224 {
225 printf(INT128_HEX_FORMAT " / signed %08X\n", t3.hl.hi, t3.hl.lo, z32);
226 printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
227 printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
228 return 1;
229 }
230 if (r1 != r2)
231 {
232 printf(INT128_HEX_FORMAT " %% signed %08X\n", t3.hl.hi, t3.hl.lo, z32);
233 printf("native = %08X\n", r1);
234 printf("result = %08X\n", r2);
235 return 1;
236 }
237
238 /* check comparison */
239 t1.hl.hi = x;
240 t1.hl.lo = y;
241 t2.hl.hi = z;
242 t2.hl.lo = w;
243
244 if (my_int128_compare(t1.i128, t2.i128) !=
245 int128_compare(t1.I128, t2.I128))
246 {
247 printf("comparison failure: %d vs %d\n",
248 my_int128_compare(t1.i128, t2.i128),
249 int128_compare(t1.I128, t2.I128));
250 printf("arg1 = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
251 printf("arg2 = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
252 return 1;
253 }
254
255 /* check case with identical hi parts; above will hardly ever hit it */
256 t2.hl.hi = x;
257
258 if (my_int128_compare(t1.i128, t2.i128) !=
259 int128_compare(t1.I128, t2.I128))
260 {
261 printf("comparison failure: %d vs %d\n",
262 my_int128_compare(t1.i128, t2.i128),
263 int128_compare(t1.I128, t2.I128));
264 printf("arg1 = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
265 printf("arg2 = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
266 return 1;
267 }
268 }
269
270 return 0;
271}
272
273#else /* ! HAVE_INT128 */
274
275/*
276 * For now, do nothing if we don't have a native int128 type.
277 */
278int
279main(int argc, char **argv)
280{
281 printf("skipping tests: no native int128 type\n");
282 return 0;
283}
284
285#endif
int64_t int64
Definition: c.h:538
int32_t int32
Definition: c.h:537
uint64_t uint64
Definition: c.h:542
static void int128_sub_uint64(INT128 *i128, uint64 v)
Definition: int128.h:158
static void int128_add_uint64(INT128 *i128, uint64 v)
Definition: int128.h:92
static void int128_sub_int64_mul_int64(INT128 *i128, int64 x, int64 y)
Definition: int128.h:266
static void int128_add_int128(INT128 *i128, INT128 v)
Definition: int128.h:144
static void int128_sub_int64(INT128 *i128, int64 v)
Definition: int128.h:179
static int int128_compare(INT128 x, INT128 y)
Definition: int128.h:425
static void int128_add_int64(INT128 *i128, int64 v)
Definition: int128.h:117
static void int128_div_mod_int32(INT128 *i128, int32 v, int32 *remainder)
Definition: int128.h:308
static void int128_add_int64_mul_int64(INT128 *i128, int64 x, int64 y)
Definition: int128.h:203
int y
Definition: isn.c:76
int x
Definition: isn.c:75
int32 pg_prng_int32(pg_prng_state *state)
Definition: pg_prng.c:243
int64 pg_prng_int64(pg_prng_state *state)
Definition: pg_prng.c:173
void pg_prng_seed(pg_prng_state *state, uint64 seed)
Definition: pg_prng.c:89
pg_prng_state pg_global_prng_state
Definition: pg_prng.c:34
#define printf(...)
Definition: port.h:266
Definition: int128.h:55
int main(int argc, char **argv)
Definition: test_int128.c:279