代码之家  ›  专栏  ›  技术社区  ›  Daniel Lemire

如果x>0并且r(x)=2x,那么实现有符号到无符号映射r(x)=2x-1的更快方法是什么?

  •  1
  • Daniel Lemire  · 技术社区  · 14 年前

    双目标映射有符号整数可以使用诸如二的补码之类的常用技术来完成。不幸的是,它们无法将小的负整数映射为小的数字。对于压缩算法,我们通常希望尽可能保留数字的绝对值:小的负数和正数必须映射到小的数字。

    如果x<0,则热门地图为r(x)=-2x-1;如果x>=0,则热门地图为r(x)=-2x-1。(如果x<=0,则R(x)=-2x;如果x>0,则为2x+1。)

    简单地实现,这个映射是相对缓慢的。当然要比将有符号整数强制转换为无符号整数慢得多(无符号整数自动应用两个补)。

    最快的方法是什么?

    3 回复  |  直到 11 年前
        1
  •  3
  •   Jens Gustedt    14 年前

    silently applies Two's complement 是的,在大多数Mondern平台上,这只是一个 nop 编译器只是以不同的方式解释您的数据。所以这真的很难击败。

    对于你的比较来说,如果你能提供一些基准点的话会很好……

    如果我没弄错的话 2 * abs(x) + signbit 可以通过循环左移位位来完成。因此,如果您的平台有这样一条指令,那么使用内联汇编程序很容易实现这一点,并且最终只会生成一条指令。

    编辑: 我错了,这件简单的事情只能和 符号与价值 负数的表示。

    如果输入为负,那么对于two的补码,您必须否定旋转的结果。类似的东西

    inline uint64_t rotateL(uint64_t x) {
      asm ("rolq %0" : "=r" (x) : "r" (x));
      return x;
    }
    
    inline uint64_t value(uint64_t x) {
      uint64_t ret = rotateL(x);
      return (ret % UINT64_C(2))
        ? -ret
        : ret;
    }
    

    我研究了GCC生产的汇编程序。看起来不错,只有5个说明

    rolq    %rax
    movq    %rax, %rdx
    negq    %rdx
    testb   $1, %al
    cmovne  %rdx, %rax
    
        2
  •  1
  •   BarsMonster    14 年前

    如果对字节进行操作,查找表必须是最快的。

    对于更大的整数,基于cmov的实现是不错的。 您也可以在这里使用SSE说明。

        3
  •  0
  •   R.. GitHub STOP HELPING ICE    14 年前

    如果您的实现支持有符号值的算术右移,请尝试以下操作:

    #define MAP(x) ((x)<<1 ^ (x)>>sizeof(x)*CHAR_BIT-1)
    

    对于没有签署右移位的实现,可以使用:

    #define RSHIFT(x,n) ((x)>>n | \
      (-(1 & (x)>>sizeof(x)*CHAR_BIT-1))<<sizeof(x)*CHAR_BIT-1-n<<1))
    

    (你应该检查这个是否正确…)