【问题标题】:calculating bit flag intersection for congruency计算位标志交集的一致性
【发布时间】:2013-02-19 14:57:45
【问题描述】:

技术情况:

Given 是 SQL Server 2008 R2 中的 int 列,用于保存十进制“编码”位标志(范围从 20 到 230,因此有 31 个可用标志,最大值为 1073741824)。此列可能包含可分配整数组合的整个范围,全部用于对单个对象进行分类。

待解决的问题:

从有限数量的十进制“位整数”中,我们必须找到一个代表所有这些标志的某种交集的数字—— 比如你有3,10,524290,很明显2应该设置在结果中,而其他位(1,8,524288)是有争议的。这是一个非常基本的例子。这可能是一组真实的输入数据(仅前两列):

发生次数 |十进制位域 |二进制表示 7 | 268435460 | 100000000000000000000000000100 5 | 268435488 | 100000000000000000000000100000 5 | 128 | 00000000000000000000010000000 4 | 32 | 000000000000000000000000100000 3 | 4 | 000000000000000000000000000100 3 | 268435492 | 10000000000000000000000100100 2 | 36 | 00000000000000000000000100100 2 | 132 | 00000000000000000000010000100 1 | 160 | 00000000000000000000010100000 特定位的出现次数:3--------------------3-6--6-- 期望的输出可能性:10000000000000000000000100100

目前的解决方案:

…在 Transact-SQL 中实现:

  1. 收集所有要计算的整数并将它们连接成一个逗号分隔的字符串。
  2. 减少字符串,取出第一个数字,循环遍历:
  3. 对照最大值 (&-AND) 检查受测者并将最大值除以 2(而 >=1)。

……到目前为止? ó.Ò

现在我有一个二进制代表的比特集的输出。我考虑将这些位保存到一个 31 列的临时表中,以便进行评估。但后来我开始想:难道没有更聪明的方法来做到这一点吗? SQL Server 速度超快,即使在反汇编 10000 个生成的整数时也是如此。但也许有一个内置函数可以计算两个二进制位标志之间的“距离”。

我承认这是一个复杂的问题,但我真的确实看到了隧道尽头的曙光,即使它需要以间接的方式完成。它会变得更加复杂,因为稍后还应该应用加权,因此 2× ¬00010000 @ 100% 显着性>00010000 @ 40% 显着性。但是,当我生成并提供摘要时,我会尝试处理这个问题

【问题讨论】:

    标签: sql-server bit-fields


    【解决方案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
    

    【讨论】:

    • 这是一个很好的方法,SELECT @i = (@i &amp; a) FROM @t 发挥了作用。乍一看,实际上分配给@i 的内容对我来说并不明显,尽管它确实产生了在@t 表中的每个整数中设置的位的十进制表示。现在想象一个像3,5,9,17,33,65,128 这样的集合。在 8 个值中的 7 个中设置了 2,但上面的解决方案除了 0 之外不会返回任何其他值。
    猜你喜欢
    • 1970-01-01
    • 2011-02-12
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    • 2022-06-11
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多