It’s not often that bit-twiddling and SQL sit well together. Different sides of the railway line and all that. However, I recently came across an interesting expression which fits the bill:
f(n) = ~n & ~(n-1)
Or in something closer to English:
f(n) = NOT n AND (NOT (n - 1))
This had me scratching my head, because while it was recognisable as something involving bit patterns, I couldn’t immediately make sense of it, even after listing out some values which made it clear that it only emits powers of two:
select n = number , [f(n)] = ~number & ~(~number - 1) from master..spt_values where type='p' and number < 2047
Here are the first few results:
n | f(n) |
---|---|
0 | 1 |
1 | 2 |
2 | 1 |
3 | 4 |
4 | 1 |
5 | 2 |
6 | 1 |
7 | 8 |
So what is the pattern here? I remained mystified until I came across Hacker’s Delight, which is indeed delightful and kicks off with a collection of very similar expressions. My brain was evaporating after a few pages, but fortunately not before I saw the pattern. Turns out that what I was looking at is the zero-based version of something that is more obvious when one-based, namely “return a mask representing the least significant bit set in the number N”. With the 1 offset applied, we get:
select n = number + 1 , [f(n)] = ~number & ~(~number - 1) from master..spt_values where type='p' and number < 2047
n | f(n) |
---|---|
1 | 1 |
2 | 2 |
3 | 1 |
4 | 4 |
5 | 1 |
6 | 2 |
7 | 1 |
8 | 8 |
Let’s think about it differently. For an ordered set of bit flags (ordered backwards in this case), this is a window function returning the first member with a given value. We’re getting into more familiar territory here. And the SQL connection runs deeper still: this expression shows up in various SQLOS methods.
However, my favourite discovery was this very eloquent picture of distribution of f(n) for the first 2^m – 1 values of n:
select [f(n)], Instances = count(*) from ( select n = number , [f(n)] = ~number & ~(~number - 1) from master..spt_values where type='p' and number < 2047 ) x group by [f(n)] order by [f(n)]
f(n) | Instances |
---|---|
1 | 1024 |
2 | 512 |
4 | 256 |
8 | 128 |
16 | 64 |
32 | 32 |
64 | 16 |
128 | 8 |
256 | 4 |
512 | 2 |
1024 | 1 |
She is one of a kind, eh?