【问题标题】:optimized byte array shifter优化的字节数组移位器
【发布时间】:2010-12-16 19:37:07
【问题描述】:

我确定之前有人问过这个问题,但我需要在可变长度大小的字节数组上实现移位运算符。我环顾四周,但没有找到任何标准的方法。我想出了一个可行的实现,但我不确定它的效率如何。有谁知道移动数组的标准方法,或者至少对如何提高我的实现性能有任何建议;

char* baLeftShift(const char* array, size_t size, signed int displacement,char* result)
{
    memcpy(result,array,size);
    short shiftBuffer = 0;
    char carryFlag = 0;
    char* byte;
    if(displacement > 0)
    {
        for(;displacement--;)
        {
            for(byte=&(result[size - 1]);((unsigned int)(byte))>=((unsigned int)(result));byte--)
            {
                shiftBuffer = *byte;
                shiftBuffer <<= 1;
                *byte = ((carryFlag) | ((char)(shiftBuffer)));
                carryFlag = ((char*)(&shiftBuffer))[1];
            }
        }
    }
    else
    {
        unsigned int offset = ((unsigned int)(result)) + size;
        displacement = -displacement;
        for(;displacement--;)
        {
            for(byte=(char*)result;((unsigned int)(byte)) < offset;byte++)
            {
                shiftBuffer = *byte;
                shiftBuffer <<= 7;
                *byte = ((carryFlag) | ((char*)(&shiftBuffer))[1]);
                carryFlag = ((char)(shiftBuffer));
            }
        }
    }
    return result;
}

【问题讨论】:

    标签: c optimization bit-manipulation


    【解决方案1】:

    如果我可以补充@dwelch 所说的话,你可以试试这个。

    1. 只需将字节移动到它们的最终位置。例如,如果每个字节仍需要左移 3 位到下一个更高的字节,则剩下的移位计数为 3。 (这假设您认为字节按从右到左升序排列。)

    2. 然后将每个字节向左旋转 3。查找表可能比单独执行实际旋转更快。然后,在每个字节中,要移位的 3 位现在位于字节的右端。

    3. 现在做一个掩码M,也就是(1&lt;&lt;3)-1,就是简单的低3位开启。

    4. 现在,按照从高位字节到低位字节的顺序,这样做:

      c[i] ^= M &amp; (c[i] ^ c[i-1])

    这会将位从 c[i-1] 复制到 c[i] 掩码 M 下。

    对于最后一个字节,只需使用 0 代替 c[i-1]

    对于右移,同样的想法。

    【讨论】:

      【解决方案2】:

      我的第一个建议是消除围绕位移的 for 循环。您应该能够在没有for(;displacement--;) 循环的情况下进行必要的转换。对于大于 7 的位移,事情会变得有点棘手,因为您的内部循环边界会发生变化,并且您的源偏移量不再是 1。即,您的输入缓冲区偏移量变为 magnitude / 8,而您的移位变为 magnitude % 8

      【讨论】:

      • 在对尾字节进行最终位移之前,我是否还需要一个循环来将字节(大小/8)地址分配给左侧?还是我对你说的有什么不明白的地方?
      【解决方案3】:

      它看起来确实效率低下,也许这就是 Nathan 所指的。

      假设运行此代码的字符为 8 位,有两件事要做首先移动整个字节,例如,如果您的输入数组是 0x00,0x00,0x12,0x34 并且您向左移动 8 位,那么您将得到 0x00 0x12 0x34 0x00,没有理由在一个循环中一次 8 次执行该操作。因此,首先将数组中的整个字符移动 (displacement>>3) 位置,然后用某种形式填充用零创建的孔 for(ra=(displacement>>3);ra>3)] = array[ra];对于(ra-=(位移>>3);ra>(7-(位移&7)))。一个好的编译器会预先计算 (displacement>>3)、displacement&7、7-(displacement&7),一个好的处理器将有足够的寄存器来保存所有这些值。您可以通过为每个项目创建单独的变量来帮助编译器,但取决于编译器以及您使用它的方式,它也可能会使情况变得更糟。

      不过,最重要的是代码时间。执行一千个 1 位移位,然后执行一千个 2 位移位,等等整个过程,然后尝试不同的算法并以相同的方式计时,看看优化是否有所作为,使其变得更好或更差。如果您提前知道此代码将仅用于单次或少于 8 位移位,请相应地调整时序测试。

      您对进位标志的使用意味着您知道许多处理器具有专门用于链接无限长移位的指令,使用标准寄存器长度(一次单个位)基本上通过进位循环。 C语言不直接支持。对于链接单个位移位,您可以考虑使用汇编程序,并且可能优于 C 代码。至少单个位移比 C 代码更快。移动字节的混合,然后如果要移位的位数(位移和 7)可能小于 4,则使用汇编程序,否则使用 C 循环。再次计时测试将告诉您优化在哪里。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-19
        • 2020-08-09
        • 1970-01-01
        • 2017-05-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多