Skip to content

Commit f0705bb

Browse files
committed
Add functions to calculate the next power of 2
There are many areas in the code where we need to determine the next highest power of 2 of a given number. We tend to always do that in an ad-hoc way each time, generally with some tight for loop which performs a bitshift left once per loop and goes until it finds a number above the given number. Here we add two generic functions which make use of the existing pg_leftmost_one_pos* functions which, when available, will allow us to calculate the next power of 2 without any looping. Here we don't add any code which uses these new functions. That will be done in follow-up commits. Author: David Fetter, with some minor adjustments by me Reviewed-by: John Naylor, Jesse Zhang Discussion: https://postgr.es/m/20200114173553.GE32763%40fetter.org
1 parent 7a5d74b commit f0705bb

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

Diff for: src/include/port/pg_bitutils.h

+72
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,78 @@ pg_rightmost_one_pos64(uint64 word)
129129
#endif /* HAVE__BUILTIN_CTZ */
130130
}
131131

132+
/*
133+
* pg_nextpower2_32
134+
* Returns the next highest power of 2 of 'num', or 'num', if it's
135+
* already a power of 2.
136+
*
137+
* 'num' mustn't be 0 or be above PG_UINT32_MAX / 2 + 1.
138+
*/
139+
static inline uint32
140+
pg_nextpower2_32(uint32 num)
141+
{
142+
Assert(num > 0 && num <= PG_UINT32_MAX / 2 + 1);
143+
144+
/*
145+
* A power 2 number has only 1 bit set. Subtracting 1 from such a number
146+
* will turn on all previous bits resulting in no common bits being set
147+
* between num and num-1.
148+
*/
149+
if ((num & (num - 1)) == 0)
150+
return num; /* already power 2 */
151+
152+
return ((uint32) 1) << (pg_leftmost_one_pos32(num) + 1);
153+
}
154+
155+
/*
156+
* pg_nextpower2_64
157+
* Returns the next highest power of 2 of 'num', or 'num', if it's
158+
* already a power of 2.
159+
*
160+
* 'num' mustn't be 0 or be above PG_UINT64_MAX / 2 + 1.
161+
*/
162+
static inline uint64
163+
pg_nextpower2_64(uint64 num)
164+
{
165+
Assert(num > 0 && num <= PG_UINT64_MAX / 2 + 1);
166+
167+
/*
168+
* A power 2 number has only 1 bit set. Subtracting 1 from such a number
169+
* will turn on all previous bits resulting in no common bits being set
170+
* between num and num-1.
171+
*/
172+
if ((num & (num - 1)) == 0)
173+
return num; /* already power 2 */
174+
175+
return ((uint64) 1) << (pg_leftmost_one_pos64(num) + 1);
176+
}
177+
178+
/*
179+
* pg_ceil_log2_32
180+
* Returns equivalent of ceil(log2(num))
181+
*/
182+
static inline uint32
183+
pg_ceil_log2_32(uint32 num)
184+
{
185+
if (num < 2)
186+
return 0;
187+
else
188+
return pg_leftmost_one_pos32(num - 1) + 1;
189+
}
190+
191+
/*
192+
* pg_ceil_log2_64
193+
* Returns equivalent of ceil(log2(num))
194+
*/
195+
static inline uint64
196+
pg_ceil_log2_64(uint64 num)
197+
{
198+
if (num < 2)
199+
return 0;
200+
else
201+
return pg_leftmost_one_pos64(num - 1) + 1;
202+
}
203+
132204
/* Count the number of one-bits in a uint32 or uint64 */
133205
extern int (*pg_popcount32) (uint32 word);
134206
extern int (*pg_popcount64) (uint64 word);

0 commit comments

Comments
 (0)