我遇到需要计算值范围的字节宽度的情况,目的是解析在串行通信链路上接收的字节。使用数据类型的宽度是不可取的,因为我最终会考虑到永远不会使用的大量字节。在我的情况下,该值将介于0和4095之间(即12位或2字节宽),但情况并非总是如此。最大值可能是255(8位或一个字节),或者就此而言为100.000(17位或3个字节)。
那么如何计算值范围的位/字节宽度?
答案 0 :(得分:2)
方法1
我的解决方案是使用微积分,并反转计算最大范围的公式:maxRange = 2^bitWidth;
给出:bitWidth = log10(maxRange) / log10(2);
或Damien_The_Unbeliever指出Math.Log()
重载:bitWidth = log2(maxRange);
然后向上舍入到最近的位,除以8并再次向上舍入,得到最接近的字节。
因此C#实现变为:
private int GetByteWidth(long maxValue)
{
int bitLength = (int)Math.Ceiling(Math.Log(ValueRangeMaximum, 2)); // Finding 2^bitLength=ValueRangeMaximum
int byteLength = (int)Math.Ceiling((double)bitLength / 8); // Rounding up to nearest byte
return byteLength;
}
一种较小的方法,用于隔离计算位宽的方法(参见有关计算的部分):
public static int CalculateBitWidthMethod1(int value)
{
int bitWidth = (int)Math.Ceiling(Math.Log(value, 2));
return bitWidth;
}
方法2
public static int CalculateBitWidthMethod2(int value)
{
int bitWidth = 1;
while ((value >>= 1) > 0)
{
bitWidth++;
}
return bitWidth;
}
<强> CALCULATIONS 强>
我创建了一个小型控制台应用程序,用于测试隔离位宽计算方法。源代码:https://github.com/ohjohnsen/BitWidthCalculations
它计算整数值1000000
的位宽一千万次,并以毫秒为单位打印经过的时间。
我的结果略有不同,但方法的整体表现如下:
答案 1 :(得分:1)
最有效的方法是使用“lzcnt” - 即“前导零计数”。 {Width minus lzcnt}告诉您使用的位的数量,“lzcnt”是CPU内在的。不幸的是,除非你使用experimental .NET Core code(目前为in "rc1"),否则CPU内在函数并不容易获得,但有一种有效的算法方法可以使用预先计算的日志表来避免昂贵的数学运算;见"Find integer log base 2", here