Обсуждение: Bit count
I'd like to use an integer column (16 bits will suffice) to hold a bit-field. I'd like to be able to efficiently count thenumber of bits set in this field. Is there a built-in function call I can use? (I can't find one in the manual). If not, can anyone recommend the most efficient way within postgres to implement the kind of bit-counting tricks found at: http://gurmeetsingh.wordpress.com/2008/08/05/fast-bit-counting-routines/ http://graphics.stanford.edu/~seander/bithacks.html Nathaniel
On Tue, Nov 24, 2009 at 16:47, Nathaniel Trellice <naptrel@yahoo.co.uk> wrote: [...] > If not, can anyone recommend the most efficient way within postgres to implement the kind of bit-counting tricks foundat: Perhaps something like this: CREATE OR REPLACE FUNCTION bitcount(i integer) RETURNS integer AS $$ DECLARE n integer; DECLARE amount integer; BEGIN amount := 0; FOR n IN 1..16 LOOP amount := amount + ((i >> (n-1)) & 1); END LOOP; RETURN amount; END $$ LANGUAGE plpgsql; bos=# select bitcount(6); bitcount ---------- 2 (1 row) bos=# select bitcount(7); bitcount ---------- 3 bos=# select bitcount(4711); bitcount ---------- 7 (1 row) bos=# select bitcount(1024); bitcount ---------- 1 (1 row) -- - Rikard
On Tue, Nov 24, 2009 at 07:18:00PM +0100, Rikard Bosnjakovic wrote: > On Tue, Nov 24, 2009 at 16:47, Nathaniel Trellice <naptrel@yahoo.co.uk> wrote: > > [...] > > If not, can anyone recommend the most efficient way within postgres to implement the kind of bit-counting tricks foundat: > > Perhaps something like this: > > CREATE OR REPLACE FUNCTION bitcount(i integer) RETURNS integer AS $$ > DECLARE n integer; > DECLARE amount integer; > BEGIN > amount := 0; > FOR n IN 1..16 LOOP > amount := amount + ((i >> (n-1)) & 1); > END LOOP; > RETURN amount; > END > $$ LANGUAGE plpgsql; > > > bos=# select bitcount(6); > bitcount > ---------- > 2 > (1 row) > > bos=# select bitcount(7); > bitcount > ---------- > 3 > > bos=# select bitcount(4711); > bitcount > ---------- > 7 > (1 row) > > bos=# select bitcount(1024); > bitcount > ---------- > 1 > (1 row) > > > -- > - Rikard > You could also setup a lookup table and just select the bit count from the table. There was also a thread on how to efficiently count the set bits that concluded with the posting of a C function that could be used. It all depends on your need for speed. Regards, Ken
On Tue, Nov 24, 2009 at 1:18 PM, Rikard Bosnjakovic <rikard.bosnjakovic@gmail.com> wrote: > On Tue, Nov 24, 2009 at 16:47, Nathaniel Trellice <naptrel@yahoo.co.uk> wrote: > > [...] >> If not, can anyone recommend the most efficient way within postgres to implement the kind of bit-counting tricks foundat: > > Perhaps something like this: > > CREATE OR REPLACE FUNCTION bitcount(i integer) RETURNS integer AS $$ > DECLARE n integer; > DECLARE amount integer; > BEGIN > amount := 0; > FOR n IN 1..16 LOOP > amount := amount + ((i >> (n-1)) & 1); > END LOOP; > RETURN amount; > END > $$ LANGUAGE plpgsql; > [snip] Clever! Here's a pure SQL version I whipped up.. perhaps there's a more efficient pure SQL way that can avoid the string operations I'm using :-) # SELECT num, char_length(replace(num::bit(16)::text, '0', '')) AS num_set_bits FROM numbers; num | num_set_bits ------+-------------- 6 | 2 7 | 3 4711 | 7 1024 | 1 Josh
On 2009-11-24, Nathaniel Trellice <naptrel@yahoo.co.uk> wrote: > I'd like to use an integer column (16 bits will suffice) to hold a bit-field. I'd like to be able to efficiently countthe number of bits set in this field. > > Is there a built-in function call I can use? (I can't find one in the manual). convert it to a text representation of the binary value use regexp_replace to remove the 0s take the length. > If not, can anyone recommend the most efficient way within postgres to implement the kind of bit-counting tricks foundat: postgres functions can be written in C (if you have superuser priviledges) seems like overkill though.
Thanks for all the replies. I'm giving this a spin, at present. It's based on Rikard's suggestion of using plpgsql script function. Like Jason and otherhave said, it could be done in a C function (and this was my first inclination), but the hassle of worrying about linkinglibraries, 32/64-bit installation etc is probably overkill. So this implementation of the 'MIT Hakmem' algorithm seemedlike a good compromise between efficiency and efficacy: CREATE FUNCTION mybitcount(n int4) RETURNS int4 AS $$ DECLARE tmp int4; BEGIN tmp = n - ((n >> 1) & 3681400539) - ((n >> 2) & 1227133513); RETURN ((tmp + (tmp >> 3)) & 3340530119) % 63; END $$ LANGUAGE plpgsql IMMUTABLE STRICT; Nathaniel