可以用Java完成5-Op Log2(Int 32)Bit Hack吗?

时间:2011-12-03 17:06:16

标签: java math optimization types bit-manipulation

只是为了澄清这不是一个功课问题,因为我已经看到类似的指责与其他一些有点讨厌的问题:

那就是说,我在C中有这样的攻击:

#include <stdio.h>

const int __FLOAT_WORD_ORDER = 0;
const int __LITTLE_END = 0;

// Finds log-base 2 of 32-bit integer
int log2hack(int v)
{
  union { unsigned int u[2]; double d; } t; // temp
  t.u[0]=0;
  t.u[1]=0;
  t.d=0.0;

  t.u[__FLOAT_WORD_ORDER==__LITTLE_END] = 0x43300000;
  t.u[__FLOAT_WORD_ORDER!=__LITTLE_END] = v;
  t.d -= 4503599627370496.0;
  return (t.u[__FLOAT_WORD_ORDER==__LITTLE_END] >> 20) - 0x3FF;
}

int main ()
{
  int i = 25; //Log2n(25) = 4
  int j = 33; //Log2n(33) = 5

  printf("Log2n(25)=%i!\n",
         log2hack(25));
  printf("Log2n(33)=%i!\n",
         log2hack(33));

  return 0;
}

我想将其转换为Java。到目前为止我所拥有的是:

public int log2Hack(int n)
    {
        int r; // result of log_2(v) goes here
        int[] u = new int [2]; 
        double d = 0.0;
        if (BitonicSorterForArbitraryN.__FLOAT_WORD_ORDER==
                BitonicSorterForArbitraryN.LITTLE_ENDIAN) 
        {
            u[1] = 0x43300000;
            u[0] = n;
        }
        else    
        {
            u[0] = 0x43300000;
            u[1] = n;
        }
        d -= 4503599627370496.0;
        if (BitonicSorterForArbitraryN.__FLOAT_WORD_ORDER==
                BitonicSorterForArbitraryN.LITTLE_ENDIAN)
            r = (u[1] >> 20) - 0x3FF;
        else
            r = (u[0] >> 20) - 0x3FF;

        return r;
    }

(注意它在我的一个比特排序类......)

无论如何,当我为相同的值33和25运行时,我在每种情况下得到52。

我知道Java的整数是签名的,所以我很确定这与失败的原因有关。有没有人有任何想法如何让这个5-op,32位整数log 2在Java中工作?

P.S。为了记录,技术不是我的,我从这里借来的: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogIEEE64Float

3 个答案:

答案 0 :(得分:5)

如果你是Java,你不能简单地31 - Integer(v).numberOfLeadingZeros()吗?如果他们使用__builtin_clz实现此功能,则应该很快。

答案 1 :(得分:0)

我认为你没有得到该代码的含义。 C代码使用 union - 一个将同一内存映射到两个或多个不同字段的结构。这使得可以访问为double分配的存储作为整数。在Java代码中,不使用union,而是使用两个映射到内存不同部分的不同变量。这使黑客失败。

由于Java没有联合,因此您必须使用序列化来获得所需的结果。由于这很慢,为什么不使用另一种方法来计算对数?

答案 2 :(得分:0)

您正在使用union将您的一对int转换为具有相同位模式的double。在Java中,您可以使用Double.longBitsToDouble执行此操作,然后使用Double.doubleToLongBits转换回来。 Java总是(或至少给人留下永远存在的印象)big-endian,所以你不需要字节序检查。

尽管如此,我尝试将您的代码调整为Java并不起作用。 Java整数的签名可能是个问题。