PostgreSQL Source Code  git master
testint128.c
Go to the documentation of this file.
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-2019, 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;
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
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
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
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 }
uint64 lo
Definition: testint128.c:44
static void int128_add_uint64(INT128 *i128, uint64 v)
Definition: int128.h:122
long random(void)
Definition: random.c:22
static int int128_compare(INT128 x, INT128 y)
Definition: int128.h:238
#define printf(...)
Definition: port.h:198
int main(int argc, char **argv)
Definition: testint128.c:89
int128 i128
Definition: testint128.c:36
static uint64 get_random_uint64(void)
Definition: testint128.c:69
INT128 I128
Definition: testint128.c:37
union test128::@170 hl
Definition: int128.h:107
static void int128_add_int64_mul_int64(INT128 *i128, int64 x, int64 y)
Definition: int128.h:177
int64 hi
Definition: testint128.c:45
static void int128_add_int64(INT128 *i128, int64 v)
Definition: int128.h:143
static int my_int128_compare(int128 x, int128 y)
Definition: testint128.c:55