【问题标题】:Bit counting arbitrarily large positive integers in C#在 C# 中对任意大的正整数进行位计数
【发布时间】:2012-08-07 12:59:40
【问题描述】:

有很多位计数的实现,但就我而言,我需要测试一个任意大的数字是否最多包含两个设置位。

我编写了以下函数来完成这项工作,而且速度似乎相当快,但我想知道它是否可以针对 C# 进一步优化。这个函数在循环中被调用了几百万次。

public static byte [] BitCountLookupArray = new byte []
{
    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};

// The parameter [number] will NEVER be negative.
public static bool HasSetBitCountOfLessThenThree (System.Numerics.BigInteger number)
{
    int sum = 0;
    byte [] bytes = null;

    bytes = number.ToByteArray();

    for (int i=0; i < bytes.Length; i++)
    {
        sum += BitCountLookupArray [bytes [i]];
    }

    return (sum < 3);
}

重要提示:发送给函数的参数 [number] 将从不为负数。

我想到的几点是:

  • 使函数静态化。完成。
  • 使用静态查找数组。完成。
  • 使用指针而不是数组索引,因为字节数经常超过 100,000。不确定这会有多大帮助。
  • 强制一个内联函数,遗憾的是在 .NET 中无法保证。

接受其他建议。

【问题讨论】:

  • 抱歉,我不确定我是否理解。你说的是位计数,但你使用的是字节?
  • @SimonWhitehead:我们正在计算比特。它们恰好可以作为字节数组使用。

标签: c# .net optimization bit-manipulation bitcount


【解决方案1】:

这样你可以进一步优化它

for (int i=0; i < bytes.Length; i++)
{
    sum += BitCountLookupArray [bytes [i]];
    if(sum >= 3)
    {
         return false   // This will stop the execution of unnecessary lines  
                        // as we need to know whether sum is less than 3 or not.                         
    }
}

return true;

【讨论】:

  • break; 更改为return false;return (sum &lt; 3); 更改为return true;。这将节省更多的周期。
  • @cadrell0:是的,那会更优化。
【解决方案2】:

由于您只需要知道您的设置位是否少于 3 个,我建议这样做:

// remove two bits
number &= number - 1;
number &= number - 1;
// if number != 0, then there were 3 or more bits set
return number.IsZero;

Rain 的方法当然也行得通,我不确定哪种策略会更快。

替代方案:

//remove one bit
number &= number - 1;
// if the number of bits left is 0 or 1, there were < 3 bits set
return number.IsZero || number.IsPowerOfTwo;

先测试可能会更快,然后再删除该位:

return number.IsZero ||        // zero bits?
    number.IsPowerOfTwo ||     // one bit?
    (number & (number - 1)).IsPowerOfTwo;  // two bits?

【讨论】:

    【解决方案3】:

    最明显的优化是在sum == 3 时立即退出循环,因为超过该点的任何进一步匹配都无关紧要。

    也不需要设置bytes两次;只需使用byte [] bytes = number.ToByteArray();,但这里的好处是微乎其微的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-25
      • 2017-04-06
      • 2012-06-18
      • 2013-10-15
      • 1970-01-01
      • 2017-07-12
      • 2023-03-28
      • 1970-01-01
      相关资源
      最近更新 更多