c#-从部分位获取整数的最快方法
我有byte[]byteArray,通常是byteArray.Length=1-3 我需要将一个数组分解为位,取一些位(例如,5-17),然后将这些位转换为Int32 我试着这么做c#-从部分位获取整数的最快方法,c#,arrays,performance,bit,C#,Arrays,Performance,Bit,我有byte[]byteArray,通常是byteArray.Length=1-3 我需要将一个数组分解为位,取一些位(例如,5-17),然后将这些位转换为Int32 我试着这么做 private static IEnumerable<bool> GetBitsStartingFromLSB(byte b) { for (int i = 0; i < 8; i++) { yield return (b % 2 != 0); b =
private static IEnumerable<bool> GetBitsStartingFromLSB(byte b)
{
for (int i = 0; i < 8; i++)
{
yield return (b % 2 != 0);
b = (byte)(b >> 1);
}
}
public static Int32 Bits2Int(ref byte[] source, int offset, int length)
{
List<bool> bools = source.SelectMany(GetBitsStartingFromLSB).ToList();
bools = bools.GetRange(offset, length);
bools.AddRange(Enumerable.Repeat(false, 32-length).ToList() );
int[] array = new int[1];
(new BitArray(bools.ToArray())).CopyTo(array, 0);
return array[0];
}
私有静态IEnumerable GetBitsStartingFromLSB(字节b)
{
对于(int i=0;i<8;i++)
{
收益率回报率(b%2!=0);
b=(字节)(b>>1);
}
}
公共静态Int32位2int(参考字节[]源,int偏移量,int长度)
{
List bools=source.SelectMany(GetBitsStartingFromLSB.ToList();
bools=bools.GetRange(偏移量、长度);
bools.AddRange(可枚举.Repeat(false,32长度).ToList());
int[]数组=新的int[1];
(新的位数组(bools.ToArray()).CopyTo(数组,0);
返回数组[0];
}
但是这个方法太慢了,我不得不经常调用它
我怎样才能更有效地做到这一点
太多了!现在我这样做:
public static byte[] GetPartOfByteArray( byte[] source, int offset, int length)
{
byte[] retBytes = new byte[length];
Buffer.BlockCopy(source, offset, retBytes, 0, length);
return retBytes;
}
public static Int32 Bits2Int(byte[] source, int offset, int length)
{
if (source.Length > 4)
{
source = GetPartOfByteArray(source, offset / 8, (source.Length - offset / 8 > 3 ? 4 : source.Length - offset / 8));
offset -= 8 * (offset / 8);
}
byte[] intBytes = new byte[4];
source.CopyTo(intBytes, 0);
Int32 full = BitConverter.ToInt32(intBytes);
Int32 mask = (1 << length) - 1;
return (full >> offset) & mask;
}
公共静态字节[]GetPartOfByteArray(字节[]源,int偏移量,int长度)
{
字节[]retBytes=新字节[长度];
Buffer.BlockCopy(源、偏移量、retBytes、0、长度);
返回retBytes;
}
公共静态Int32位2int(字节[]源,int偏移量,int长度)
{
如果(source.Length>4)
{
source=GetPartOfByteArray(source,offset/8,(source.Length-offset/8>3?4:source.Length-offset/8));
偏移量-=8*(偏移量/8);
}
字节[]intBytes=新字节[4];
source.CopyTo(整数字节,0);
Int32 full=位转换器.ToInt32(intBytes);
Int32掩码=(1>偏移量)&掩码;
}
而且它工作得非常快 如果您想要“快速”,那么最终需要使用位逻辑,而不是LINQ等。我不打算编写实际代码,但您需要:
- 使用偏移量与
和/8
一起查找起始字节和该字节内的位偏移量%8
- 无论需要多少字节,都可以组合—如果在32位数字之后,很可能最多5个字节(因为可能存在偏移)
; 例如,转换成一个
,以您期望的任何一个尾端(大概是大尾端?)为准长的
- 在合成值上使用右移(
)可以删除应用位偏移量所需的位数(即>
)值>>=偏移量%8;
- 掩盖你不想要的任何东西;例如,
value&=~-1L首先,你要求优化。但你所说的只有:
- 太慢
- 需要经常打电话吗
- 有多慢就是太慢?你测量过当前的代码吗?你估计过你需要多快吗
- “经常”是多久一次
- 源byt阵列有多大
- 等等
private static IEnumerable<bool> GetBitsStartingFromLSB(byte b) // A { for (int i = 0; i < 8; i++) { yield return (b % 2 != 0); // A b = (byte)(b >> 1); } } public static Int32 Bits2Int(ref byte[] source, int offset, int length) { List<bool> bools = source.SelectMany(GetBitsStartingFromLSB).ToList(); //A,B bools = bools.GetRange(offset, length); //B bools.AddRange(Enumerable.Repeat(false, 32-length).ToList() ); //C int[] array = new int[1]; //D (new BitArray(bools.ToArray())).CopyTo(array, 0); //D return array[0]; //D }
答:LINQ很有趣,但除非小心操作,否则不会很快。对于每个输入字节,它需要1个字节,将其拆分为8个布尔值,并将其传递给编译器生成的IEnumerable对象*)。请注意,所有这些也需要稍后清理。只需返回私有静态IEnumerable GetBitsStartingFromLSB(字节b)//A { 对于(int i=0;i<8;i++) { 收益率回报率(b%2!=0);//A b=(字节)(b>>1); } } 公共静态Int32位2int(参考字节[]源,int偏移量,int长度) { List bools=source.SelectMany(GetBitsStartingFromLSB.ToList();//A,B bools=bools.GetRange(偏移量,长度);//B bools.AddRange(Enumerable.Repeat(false,32长度).ToList());//C int[]数组=新的int[1];//D (新的位数组(bools.ToArray()).CopyTo(数组,0);//D 返回数组[0];//D }
或甚至新bool[8]
,您可能会获得更好的性能 *)在概念上。事实上,yield-return是惰性的,所以生成项的不是8valueobj+1refobj,而是1个可枚举项。但是,你在(B)中做了。ToList(),所以我用这种方式写这篇文章与事实并不遥远 A2:8是硬编码的。一旦您删除了这个漂亮的IEnumerable并将其更改为一个大小恒定的数组,您就可以预先分配该数组,并通过参数将其传递给GetBitsStartingFromLSB,以进一步减少创建的临时对象的数量,以及后来丢弃的临时对象的数量。由于SelectMany一个接一个地访问项目而不必返回,因此预分配的数组可以重用 B:将整个源数组转换为字节流,将其转换为列表。然后丢弃整个列表,除了该列表的小偏移长度范围。为什么要隐姓埋名?这只是又浪费了一包对象,内部数据也被复制了,因为位数组(size=8)
是一个valuetype。您可以直接从IEnumerable by.Skip(X).Take(Y)中获取范围 C:将布尔列表填充为32项。AddRange/Repeat很有趣,但Repeat必须返回IEnumerable。它又是另一个被创建并丢弃的对象。您正在使用bool
填充列表。放弃这个想法,把它变成一个傻瓜[32]。或位数组(32)。它们自动以false
开头。这是false
的默认值。迭代“范围”A+B中的这些位,并按索引将它们写入该数组。写的有价值,不写的有虚假。工作完成,没有浪费任何物品 C2:将预分配的32项数组与A+A2连接。GetBitsStartingFromLSB不需要返回任何内容,它可以通过参数获得要填充的缓冲区。缓冲区不需要是8项bubool