【问题标题】:Summing N arrays of bytes efficiently有效地对 N 个字节数组求和
【发布时间】:2019-09-24 09:43:43
【问题描述】:

下面是可视化需要做什么的代码。我正在寻找一种可以更快完成的解决方案。其中之一是使用位操作 (https://stackoverflow.com/a/55945544/4791668) 对数组求和。我想知道是否有任何方法可以按照链接中描述的方式进行操作并同时找到平均值。

    var random = new Random();
    byte[] bytes = new byte[20_000_000]; 
    byte[] bytes2 = new byte[20_000_000];

    for (int i = 0; i < bytes.Length; i++)
    {
        bytes[i] = (byte)random.Next(255);
    }

    for (int i = 0; i < bytes.Length; i++)
    {
        bytes2[i] = (byte)random.Next(255);
    }

    //how to optimize the part below
    for (int i = 0; i < bytes.Length; i++)
    {
        bytes[i] = (byte)((bytes[i] + bytes2[i]) / 2);
    }

/////////// 需要改进的解决方案。它没有做平均部分。

    var random = new Random();
    byte[] bytes = new byte[20_000_000]; 
    byte[] bytes2 = new byte[20_000_000];

    int Len = bytes.Length >> 3; // >>3 is the same as / 8

    ulong MASK =    0x8080808080808080;
    ulong MASKINV = 0x7f7f7f7f7f7f7f7f;

    //Sanity check
    if((bytes.Length & 7) != 0) throw new Exception("bytes.Length is not a                 multiple of 8");
    if((bytes2.Length & 7) != 0) throw new Exception("bytes2.Length is not a multiple of 8");

    unsafe
    {
//Add 8 bytes at a time, taking into account overflow between bytes
       fixed (byte* pbBytes = &bytes[0])
       fixed (byte* pbBytes2 = &bytes2[0])
       {
          ulong* pBytes = (ulong*)pbBytes;
          ulong* pBytes2 = (ulong*)pbBytes2;
          for (int i = 0; i < Len; i++)
          {
            pBytes[i] = ((pBytes2[i] & MASKINV) + (pBytes[i] & MASKINV)) ^ ((pBytes[i] ^ pBytes2[i]) & MASK);
          } 
       }        
    }

【问题讨论】:

  • I am looking for a solution that can do it faster,那么您的代码有效吗?如果是这样,最好在Code Review...
  • @Çöđěxěŕ,现在应该。谢谢。
  • 您的不安全代码如何处理/2
  • @NetMage 没有。这正是我想问的是否可以通过这个算法来完成。

标签: c# arrays bit-manipulation byte


【解决方案1】:

使用位操作,您可以并行计算字节的平均值:

ulong NOLOW = 0xfefefefefefefefe;
unsafe {
    //Add 8 bytes at a time, taking into account overflow between bytes
    fixed (byte* pbBytes = &bytes[0])
    fixed (byte* pbBytes2 = &bytes2[0])
    fixed (byte* pbAns2 = &ans2[0]) {
        ulong* pBytes = (ulong*)pbBytes;
        ulong* pBytes2 = (ulong*)pbBytes2;
        ulong* pAns2 = (ulong*)pbAns2;
        for (int i = 0; i < Len; i++) {
            pAns2[i] = (pBytes2[i] & pBytes[i]) + (((pBytes[i] ^ pBytes2[i]) & NOLOW) >> 1);
        }
    }
}

我修改了代码以存储在单独的ans 字节数组中,因为我需要源数组来比较这两种方法。显然,如果需要,您可以存储回原来的 bytes[]

这是基于以下公式:x+y == (x&amp;y)+(x|y) == (x&amp;y)*2 + (x^y) == (x&amp;y)&lt;&lt;1 + (x^y),这意味着您可以计算 (x+y)/2 == (x&amp;y)+((x^y) &gt;&gt; 1)。因为我们知道我们一次计算 8 个字节,所以我们可以屏蔽每个字节的低位,因此当我们移位所有 8 个字节时,我们将每个字节的高位移入 0 位。

在我的 PC 上,它的运行速度比(字节)总和快 2 到 3 倍(对于更长的数组趋向于 2 倍)。

【讨论】:

    猜你喜欢
    • 2020-01-30
    • 2018-08-09
    • 1970-01-01
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 2015-11-15
    • 2014-09-21
    • 1970-01-01
    相关资源
    最近更新 更多