快速二进制数字计数器64位数字c#

时间:2014-02-18 02:27:58

标签: c# performance binary counter ulong

我试着在任何地方找到解决方案。 我的请求是找到一个非常快速的算法代码,以获得无符号64位积分器(ulong)的二进制表示中的位数。

例如:

127 = 7 binary digits.

153 = 8 binary digits.

我现在找到了两种方法来获得这个。

  • 通过在字符串中修剪二进制表示,并使用“.Length”属性。
  • 获得不超过数字的2的最大功率。结果是二进制表示的最后一个位置,如果添加1(表示2 ^ 0),也表示位数

这两种方式都很好,但是当数字很大时计算时间太长。在10.000.000.000(10亿)之后,你必须计算花费的时间,而不是毫秒,这对于其余代码的性能来说是如此糟糕。

非常感谢并且对此演示文稿感到抱歉,这是通过电话编写的,而且我没有所有的工具来表达这一点。

编辑1

深入了解Bithacks网站并将速度作为首要任务。我想我将Lookup table方法与De Bruijn sequence实施一起使用。

正如我发现here:具有2 ^ 6的64位的查找表应该是这样的。

static readonly int[] MultiplyDeBruijnBitPosition2 = new int[64]
{
  0,1,2,4,8,17,34,5,11,23,47,31,63,62,61,59,
  55,46,29,58,53,43,22,44,24,49,35,7,15,30,60,57,
  51,38,12,25,50,36,9,18,37,10,21,42,20,41,19,39,
  14,28,56,48,33,3,6,13,27,54,45,26,52,40,16,32
};

基于此,来自Stackoverflow的用户“R ..”,他在C#中创建自己的paramether应该是这样的:

public static int GetLog2_DeBruijn(ulong v)
{
return MultiplyDeBruijnBitPosition2[(ulong)(v * 0x022fdd63cc95386dull) >> 58];
}

结果真的很快但错了,我不确切知道为什么。 PD:正如您所看到的“0x022fdd63cc95386dull”是128位,C#的接受代码是“0x022fdd63cc95386d”。与查找表here中显示的内容相同。

我认为因为我不能在C#中使用“0x022fdd63cc95386dull”,所以我必须使用另一个数字而不是58,或者可能是一个完全不同的十六进制64位乘数。

到目前为止,输入的数字为:17012389719861204799(使用了64位)

  • 使用pow2方法,我在1380ms内获得了64万次的结果。
  • 使用DeBruijn方法我在32ms内得到结果40 1百万次。 (不知道为什么40)

2 个答案:

答案 0 :(得分:5)

根据bit twiddling hack page,您可以找到最高位设置如下:

uint v;
uint r;
uint shift;

r =     (uint)((v > 0xFFFF) ? 1 : 0) << 4; v >>= (int)r;
shift = (uint)((v > 0xFF  ) ? 1 : 0) << 3; v >>= (int)shift; r |= shift;
shift = (uint)((v > 0xF   ) ? 1 : 0) << 2; v >>= (int)shift; r |= shift;
shift = (uint)((v > 0x3   ) ? 1 : 0) << 1; v >>= (int)shift; r |= shift;
                                        r |= (v >> 1);
// At this point r has the result

Here is a demo on ideone.

答案 1 :(得分:0)

尝试将2平方到小于您考虑的数字的最大值。然后移动该数字计数(2^n平方步骤后n个数字),并重复,总计数字计数。这应该是一个订单log log n进程。