gpt4 book ai didi

c# - 围绕对角线镜像位矩阵的性能改进

转载 作者:太空狗 更新时间:2023-10-29 21:44:45 24 4
gpt4 key购买 nike

我有一些代码可以管理从一组传感器接收到的数据。控制传感器的 PIC 使用 8 个 SAR-ADC 并行读取 4096 个数据字节。这意味着它读取前 8 个字节的最高有效位;然后它读取他们的第二位,依此类推,直到第八位(最低有效位)。

基本上,对于它读取的每 8 个字节,它会创建(并发送到计算机)8 个字节,如下所示:

// rxData[0] = MSB[7] MSB[6] MSB[5] MSB[4] MSB[3] MSB[2] MSB[1] MSB[0]
// rxData[1] = B6[7] B6[6] B6[5] B6[4] B6[3] B6[2] B6[1] B6[0]
// rxData[2] = B5[7] B5[6] B5[5] B5[4] B5[3] B5[2] B5[1] B5[0]
// rxData[3] = B4[7] B4[6] B4[5] B4[4] B4[3] B4[2] B4[1] B4[0]
// rxData[4] = B3[7] B3[6] B3[5] B3[4] B3[3] B3[2] B3[1] B3[0]
// rxData[5] = B2[7] B2[6] B2[5] B2[4] B2[3] B2[2] B2[1] B2[0]
// rxData[6] = B1[7] B1[6] B1[5] B1[4] B1[3] B1[2] B1[1] B1[0]
// rxData[7] = LSB[7] LSB[6] LSB[5] LSB[4] LSB[3] LSB[2] LSB[1] LSB[0]

对于系统读取和我处理的所有 4096 字节重复此模式。

想象一下,读取的每 8 个字节都是单独读取的,然后我们可以将它们视为一个 8×8 位数组。我需要围绕从左下角 (LSB[7]) 到右上角 (MSB[0]) 的对角线镜像此数组。完成此操作后,生成的 8×8 位数组在其行中包含从传感器读取的正确数据字节。我曾经在 PIC Controller 上执行此操作,使用左移等,但这大大降低了系统速度。因此,此操作现在在我们处理数据的计算机上执行,使用以下代码:

BitArray ba = new BitArray(rxData);
BitArray ba2 = new BitArray(ba.Count);
for (int i = 0; i < ba.Count; i++)
{
ba2[i] = ba[(((int)(i / 64)) + 1) * 64 - 1 - (i % 8) * 8 - (int)(i / 8) + ((int)(i / 64)) * 8];
}
byte[] data = new byte[rxData.Length];
ba2.CopyTo(data, 0);

请注意,此代码有效。

rxData 是接收到的字节数组。

我在上述数组镜像循环代码中用于 ba[] 索引的公式。在别处检查数组的大小,以确保它始终包含正确的字节数 (4096)。

到目前为止,这是我的问题的背景。

在我系统的每个处理循环中,我需要执行两次镜像,因为我的数据处理是基于连续获取的两个数组之间的差异。速度对我的系统很重要(可能是对处理的主要限制),镜像占我处理执行时间的 10% 到 30%。

我想知道是否有替代解决方案可以与我的镜像代码进行比较,并且可以让我提高性能。使用 BitArrays 是我发现对接收到的字节中的不同位进行寻址的唯一方法。

最佳答案

在单独的位上操作非常慢,创建 2 位数组和来回复制数据会产生更多的开销

最简单明显的解决方案就是提取位并再次组合它们。您可以使用循环来完成,但由于它同时使用左移和右移,因此您需要一个函数来处理负移量。因此我在这里展开它是为了更容易理解和更快

out[0] = (byte)(((rxData[0] & 0x80) >> 0) | ((rxData[1] & 0x80) >> 1) | ((rxData[2] & 0x80) >> 2) | ((rxData[3] & 0x80) >> 3) |
((rxData[4] & 0x80) >> 4) | ((rxData[5] & 0x80) >> 5) | ((rxData[6] & 0x80) >> 6) | ((rxData[7] & 0x80) >> 7));

out[1] = (byte)(((rxData[0] & 0x40) << 1) | ((rxData[1] & 0x40) >> 0) | ((rxData[2] & 0x40) >> 1) | ((rxData[3] & 0x40) >> 2) |
((rxData[4] & 0x40) >> 3) | ((rxData[5] & 0x40) >> 4) | ((rxData[6] & 0x40) >> 5) | ((rxData[7] & 0x40) >> 6));

out[2] = (byte)(((rxData[0] & 0x20) << 2) | ((rxData[1] & 0x20) << 1) | ((rxData[2] & 0x20) >> 0) | ((rxData[3] & 0x20) >> 1) |
((rxData[4] & 0x20) >> 2) | ((rxData[5] & 0x20) >> 3) | ((rxData[6] & 0x20) >> 4) | ((rxData[7] & 0x20) >> 5));

out[3] = (byte)(((rxData[0] & 0x10) << 3) | ((rxData[1] & 0x10) << 2) | ((rxData[2] & 0x10) << 1) | ((rxData[3] & 0x10) >> 0) |
((rxData[4] & 0x10) >> 1) | ((rxData[5] & 0x10) >> 2) | ((rxData[6] & 0x10) >> 3) | ((rxData[7] & 0x10) >> 4));

out[4] = (byte)(((rxData[0] & 0x08) << 4) | ((rxData[1] & 0x08) << 3) | ((rxData[2] & 0x08) << 2) | ((rxData[3] & 0x08) << 1) |
((rxData[4] & 0x08) >> 0) | ((rxData[5] & 0x08) >> 1) | ((rxData[6] & 0x08) >> 2) | ((rxData[7] & 0x08) >> 3));

out[5] = (byte)(((rxData[0] & 0x04) << 5) | ((rxData[1] & 0x04) << 4) | ((rxData[2] & 0x04) << 3) | ((rxData[3] & 0x04) << 2) |
((rxData[4] & 0x04) << 1) | ((rxData[5] & 0x04) >> 0) | ((rxData[6] & 0x04) >> 1) | ((rxData[7] & 0x04) >> 2));

out[6] = (byte)(((rxData[0] & 0x02) << 6) | ((rxData[1] & 0x02) << 5) | ((rxData[2] & 0x02) << 4) | ((rxData[3] & 0x02) << 3) |
((rxData[4] & 0x02) << 2) | ((rxData[5] & 0x02) << 1) | ((rxData[6] & 0x02) >> 0) | ((rxData[7] & 0x02) >> 1));

out[7] = (byte)(((rxData[0] & 0x01) << 7) | ((rxData[1] & 0x01) << 6) | ((rxData[2] & 0x01) << 5) | ((rxData[3] & 0x01) << 4) |
((rxData[4] & 0x01) << 3) | ((rxData[5] & 0x01) << 2) | ((rxData[6] & 0x01) << 1) | ((rxData[7] & 0x01) >> 0));

显然这仍然很慢,因为它是逐字节操作的。最佳解决方案是一次对多个字节进行操作,例如 SIMD和/或 multithreading .特别是因为您正在为大量数据执行此操作,.NET SIMD intrinsics会非常有用

关于c# - 围绕对角线镜像位矩阵的性能改进,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21745008/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com