SatCat5
utils.cc
1 // Copyright 2021-2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <satcat5/utils.h>
7 
8 namespace util = satcat5::util;
9 
10 // Use GCC intrinsics where possible?
11 #ifndef SATCAT5_GCC_INTRINSICS
12  #if defined(__GNUC__)
13  #define SATCAT5_GCC_INTRINSICS 1
14  #else
15  #define SATCAT5_GCC_INTRINSICS 0
16  #endif
17 #endif
18 
19 // Instantiate the global PRNG object.
21 
22 u32 util::max_u32(u32 a, u32 b, u32 c) {
23  if ((a > b) && (a > c)) return a;
24  if (b > c) return b;
25  return c;
26 }
27 
28 // Check if A is a multiple of B:
29 bool util::is_multiple_u32(u32 a, u32 b) {
30  u32 c = (a / b) * b;
31  return (a == c) ? 1 : 0;
32 }
33 
34 // Count the number of '1' bits in an integer.
35 unsigned util::popcount(u32 x) {
36 #if SATCAT5_GCC_INTRINSICS
37  // On GCC and similar, use the built-in popcount function.
38  return (unsigned)__builtin_popcount(x);
39 #else
40  // Otherwise, use a regular function definition.
41  // https://stackoverflow.com/questions/109023/
42  x = x - ((x >> 1) & 0x55555555); // Add pairs of bits
43  x = (x & 0x33333333) + ((x >> 2) & 0x33333333); // Quads
44  x = (x + (x >> 4)) & 0x0F0F0F0F; // Groups of 8
45  x *= 0x01010101; // Horizontal sum of bytes
46  return x >> 24; // Return the top byte
47 #endif
48 }
49 
50 // XOR-reduction of all bits in a word (returns 1/0).
51 bool util::xor_reduce_u8(u8 x) {
52  u8 result = 0;
53  for (unsigned b = 0 ; b < 8 ; ++b)
54  result ^= ((x >> b) & 1);
55  return result ? 1 : 0;
56 }
57 bool util::xor_reduce_u16(u16 x) {
58  u16 result = 0;
59  for (unsigned b = 0 ; b < 16 ; ++b)
60  result ^= ((x >> b) & 1);
61  return result ? 1 : 0;
62 }
63 bool util::xor_reduce_u32(u32 x) {
64  u32 result = 0;
65  for (unsigned b = 0 ; b < 32 ; ++b)
66  result ^= ((x >> b) & 1);
67  return result ? 1 : 0;
68 }
69 bool util::xor_reduce_u64(u64 x) {
70  u64 result = 0;
71  for (unsigned b = 0 ; b < 64 ; ++b)
72  result ^= ((x >> b) & 1);
73  return result ? 1 : 0;
74 }
75 
76 // Given X and Y, find the minimum N such that X * 2^N >= Y.
77 unsigned util::min_2n(u32 x, u32 y) {
78  static const u32 HALF_MAX = (1u << 31);
79 
80  // Detect invalid input (i.e., divide by zero).
81  // Undefined, just do anything that avoids an infinite loop.
82  if (x == 0) ++x;
83 
84  // Increment N until constraint is *almost* met.
85  // (Stop just short to avoid overflow when Y is very large.)
86  unsigned n = 0;
87  while ((x < HALF_MAX) && (2*x < y)) {
88  x *= 2;
89  ++n;
90  }
91 
92  // One last increment if needed.
93  if (x < y) ++n;
94  return n;
95 }
96 
97 // Find integer square root y = floor(sqrt(x))
98 // https://stackoverflow.com/questions/4930307/fastest-way-to-get-the-integer-part-of-sqrtn
99 u32 util::sqrt_u64(u64 x) {
100  u64 rem = 0, root = 0;
101  for (unsigned i = 0 ; i < 32 ; ++i) {
102  root <<= 1;
103  rem <<= 2;
104  rem += (x >> 62);
105  x <<= 2;
106 
107  if (root < rem) {
108  root++;
109  rem -= root;
110  root++;
111  }
112  }
113  return (u32) (root >> 1);
114 }
115 u16 util::sqrt_u32(u32 x) {
116  u32 rem = 0, root = 0;
117  for (unsigned i = 0 ; i < 16 ; ++i) {
118  root <<= 1;
119  rem <<= 2;
120  rem += (x >> 30);
121  x <<= 2;
122 
123  if (root < rem) {
124  root++;
125  rem -= root;
126  root++;
127  }
128  }
129  return (u16) (root >> 1);
130 }
131 u8 util::sqrt_u16(u16 x) {
132  u16 rem = 0, root = 0;
133  int i;
134  for (i = 0 ; i < 8 ; ++i) {
135  root <<= 1;
136  rem <<= 2;
137  rem += (x >> 14);
138  x <<= 2;
139 
140  if (root < rem) {
141  root++;
142  rem -= root;
143  root++;
144  }
145  }
146  return (u8) (root >> 1);
147 }
148 
149 
150 // Extract fields from a big-endian byte array.
151 u16 util::extract_be_u16(const u8* src) {
152  return 256 * (u16)src[0]
153  + 1 * (u16)src[1];
154 }
155 u32 util::extract_be_u32(const u8* src) {
156  return 16777216 * (u32)src[0]
157  + 65536 * (u32)src[1]
158  + 256 * (u32)src[2]
159  + 1 * (u32)src[3];
160 }
161 u64 util::extract_be_u64(const u8* src) {
162  return 72057594037927936ull * (u64)src[0]
163  + 281474976710656ull * (u64)src[1]
164  + 1099511627776ull * (u64)src[2]
165  + 4294967296ull * (u64)src[3]
166  + 16777216ull * (u64)src[4]
167  + 65536ull * (u64)src[5]
168  + 256ull * (u64)src[6]
169  + 1ull * (u64)src[7];
170 }
171 
172 // Store fields into a big-endian byte array.
173 void util::write_be_u16(u8* dst, u16 val) {
174  dst[0] = (u8)(val >> 8);
175  dst[1] = (u8)(val >> 0);
176 }
177 void util::write_be_u32(u8* dst, u32 val) {
178  dst[0] = (u8)(val >> 24);
179  dst[1] = (u8)(val >> 16);
180  dst[2] = (u8)(val >> 8);
181  dst[3] = (u8)(val >> 0);
182 }
183 void util::write_be_u64(u8* dst, u64 val) {
184  dst[0] = (u8)(val >> 56);
185  dst[1] = (u8)(val >> 48);
186  dst[2] = (u8)(val >> 40);
187  dst[3] = (u8)(val >> 32);
188  dst[4] = (u8)(val >> 24);
189  dst[5] = (u8)(val >> 16);
190  dst[6] = (u8)(val >> 8);
191  dst[7] = (u8)(val >> 0);
192 }
193 
195  // Marsaglia's XORSHIFT algorithm:
196  m_state ^= (m_state >> 12);
197  m_state ^= (m_state << 25);
198  m_state ^= (m_state >> 27);
199  u64 next = m_state * 0x2545F4914F6CDD1Dull;
200  return (u32)(next >> 32);
201 }
202 
203 u32 util::Prng::next(u32 mn, u32 mx) {
204  u64 scale = next() * (1ull + u64(mx) - u64(mn));
205  return mn + u32(scale >> 32);
206 }
207 
208 static const char* LABEL_NONE = "None";
209 
210 util::RunningMax::RunningMax()
211  : m_label(LABEL_NONE)
212  , m_maximum(0)
213 {
214  // Nothing else to initialize
215 }
216 
218  m_label = LABEL_NONE;
219  m_maximum = 0;
220 }
221 
222 void util::RunningMax::update(const char* lbl, u32 value) {
223  if (value > m_maximum) {
224  m_label = lbl;
225  m_maximum = value;
226  }
227 }
Simple cross-platform psuedorandom number generator (PRNG).
Definition: utils.h:370
u32 next()
Range [0..2^32)
Definition: utils.cc:194
void clear()
Reset recorded maximum to zero.
Definition: utils.cc:217
void update(const char *lbl, u32 value)
Update stats if new value exceeds previous record.
Definition: utils.cc:222
Miscellaneous mathematical utility functions.
unsigned popcount(u32 x)
Count the number of '1' bits in an integer.
Definition: utils.cc:35
u64 extract_be_u64(const u8 *src)
Extract fields from a big-endian byte array.
Definition: utils.cc:161
void write_be_u16(u8 *dst, u16 val)
Store fields into a big-endian byte array.
Definition: utils.cc:173
bool xor_reduce_u8(u8 x)
XOR-reduction of all bits in a word:
Definition: utils.cc:51
bool xor_reduce_u64(u64 x)
XOR-reduction of all bits in a word:
Definition: utils.cc:69
u32 sqrt_u64(u64 x)
Find integer square root y = floor(sqrt(x))
Definition: utils.cc:99
void write_be_u32(u8 *dst, u32 val)
Store fields into a big-endian byte array.
Definition: utils.cc:177
u8 sqrt_u16(u16 x)
Find integer square root y = floor(sqrt(x))
Definition: utils.cc:131
bool xor_reduce_u16(u16 x)
XOR-reduction of all bits in a word:
Definition: utils.cc:57
bool is_multiple_u32(u32 a, u32 b)
Check if A is a multiple of B:
Definition: utils.cc:29
satcat5::util::Prng prng
Global instance of the Prng class.
Definition: utils.cc:20
constexpr u32 max_u32(u32 a, u32 b)
Min and max functions.
Definition: utils.h:118
u32 extract_be_u32(const u8 *src)
Extract fields from a big-endian byte array.
Definition: utils.cc:155
void write_be_u64(u8 *dst, u64 val)
Store fields into a big-endian byte array.
Definition: utils.cc:183
u16 extract_be_u16(const u8 *src)
Extract fields from a big-endian byte array.
Definition: utils.cc:151
bool xor_reduce_u32(u32 x)
XOR-reduction of all bits in a word:
Definition: utils.cc:63
u16 sqrt_u32(u32 x)
Find integer square root y = floor(sqrt(x))
Definition: utils.cc:115
unsigned min_2n(u32 x, u32 y)
Given X and Y, find the minimum N such that X * 2^N >= Y.
Definition: utils.cc:77