вычисление пересечения битовых флагов для конгруэнтности
Технические обстоятельства:
Дан столбец int
в SQL Server 2008 R2 для сохранения десятичных" закодированных " битовых флагов (начиная от 20 чтобы 230, таким образом, имея 31 доступный флаг с максимумом 1073741824
). Этот столбец может содержать весь диапазон выделяемых целочисленных комбинаций, все для классификации одного объекта.
Задача, подлежащая решению:
Из конечного количества десятичных "битовых целых чисел" мы должны найти один число, которое представляет собой своего рода пересечение всех этих флагов –
например, когда у вас есть 3,10,524290
, очевидно, что 2
должно быть установлено в результате, в то время как другие биты (1,8,524288
) спорны. Это очень простой пример. Это может быть реальный набор входных данных (только первые два столбца):
Occurences | Decimal bit field | Binary representation 7 | 268435460 | 10000000000000000000000000100 5 | 268435488 | 10000000000000000000000100000 5 | 128 | 00000000000000000000010000000 4 | 32 | 00000000000000000000000100000 3 | 4 | 00000000000000000000000000100 3 | 268435492 | 10000000000000000000000100100 2 | 36 | 00000000000000000000000100100 2 | 132 | 00000000000000000000010000100 1 | 160 | 00000000000000000000010100000 Occurences of particular bit: 3--------------------3-6--6-- Desired output possibility: 10000000000000000000000100100
Решение пока:
... реализовано в Transact-SQL:
- соберите все целые числа, подлежащие вычислению, и объедините их в запятую строка.
- сокращение строки, вынимание первого числа, циклическое перебирание:
- проверка испытуемого по максимальному значению (
&-AND
) и деление максимума на 2 (пока>=1
).
... пока? о.*
Теперь у меня есть выход двоичных представителей для набора битов. Я рассматриваю возможность сохранения этих битов во временную таблицу с 31 столбцом, чтобы перейти к оценке. Но потом я подумал: а нет ли более умного способа сделать это? SQL Server работает очень быстро, даже когда разборка 10000 сгенерированных целых чисел. Но, возможно, есть встроенная функция для вычисления "расстояния" между двумя двоичными битовыми флагами.
Я признаю, что это сложная проблема, но я действительно вижу свет в конце туннеля, даже когда это нужно сделать косвенным путем. Это будет еще сложнее, так как утяжеление также должно быть применено позже, так что 2×00010000
@ 100% значение > 4× 00010000
@ 40% значение. Но я постараюсь разобраться с этим. это когда у меня есть сводка, сгенерированная и доступная 1 ответ:
Вы можете использовать побитовое и для ваших операций
declare @i int declare @x int declare @cnt int select @i=2147483647 -- 1111111 11111111 11111111 11111111 declare @t table (a int) insert into @t values( 3),(10),(524290); Select @i= (@i & a) from @t -- just for fun an output set @x=1 set @cnt=0 While @cnt<31 begin Print Case when @x & @i <> 0 then 'X' else ' ' end +' ' + Cast(@x as Varchar(12)) Set @cnt=@cnt + 1 if @cnt<31 Set @x=@x*2 end
Или с более приятным выходом
declare @i int declare @x int declare @cnt int select @i=2147483647 -- 1111111 11111111 11111111 11111111 Declare @ref table(ref int) set @x=1 set @cnt=0 While @cnt<31 begin insert into @ref Values(@x) Set @cnt=@cnt + 1 if @cnt<31 Set @x=@x*2 end declare @t table (a int) insert into @t values( 3),(10),(524290); Select @i= (@i & a) from @t Select * from @ref where ref&@i<>0
Как ответ на ваш комментарий
declare @i int declare @x int declare @cnt int select @i=2147483647 -- 1111111 11111111 11111111 11111111 Declare @ref table(ref int) set @x=1 set @cnt=0 While @cnt<31 begin insert into @ref Values(@x) Set @cnt=@cnt + 1 if @cnt<31 Set @x=@x*2 end declare @t table (a int) insert into @t values( 3),(5),(9),(17),(33),(65),(128); Select @i= (@i & a) from @t Select a,Count(*) as BitCount from @ref r join @t t on t.a & r.ref<>0 group by a Select ref,Count(*) as OCC from @ref r join @t t on t.a & r.ref<>0 group by ref Select ref,(Select count(*) from @t where a & r.ref<>0) as OCC from @ref r