2011-03-11 48 views
5

有没有办法在java中创建一个128位的对象,可以像long或int一样操作位操作?我想做32位移位,我想能够对整个128位结构进行一次或运算。java 128位结构位maninpulation

回答

2

在这里,我向你介绍......一个古老的想法。现在它被降级(没有代码增强器,没有任何代码)到简单的128位应该超快速的东西。我真正想要的是基于ByteBuffer的C类似Struct的数组,但在java中完全可用。

主要思想是一次分配多个对象并使用指向数组的指针。因此,它极大地节省了内存,并且内存分配在连续的区域,所以缓存未命中(总是很好)。

我做了一些适度的测试(但代码仍未测试)。 它确实允许基本操作,比如add,xor或者设置/获取128位数字。 标准规则:不幸的是应用文档少于预期。 为额外操作添加额外的代码应该很简单。

这里是代码,看一些用法的主要方法。干杯!

package bestsss.util; 

import java.util.Random; 

public class Bitz { 
    final int[] array; 
    private Bitz(int n){ 
     array=new int[n<<2]; 
    } 

    public int size(){ 
     return size(this.array); 
    } 

    private static int size(int[] array){ 
     return array.length>>2; 
    } 
    /** 
    * allocates N 128bit elements. newIdx to create a pointer 
    * @param n 
    * @return 
    */ 
    public static Bitz allocate(int n){ 
     return new Bitz(n); 
    } 
    /** 
    * Main utility class - points to an index in the array 
    * @param idx 
    * @return 
    */ 
    public Idx newIdx(int idx){  
     return new Idx(array).set(idx); 
    } 

    public static class Idx{ 
     private static final long mask = 0xFFFFFFFFL; 
     //dont make the field finals 

     int idx; 
     int[] array;//keep ref. here, reduce the indirection 

     Idx(int[] array){ 
      this.array=array; 
     } 

     public Idx set(int idx) { 
      if (Bitz.size(array)<=idx || idx<0) 
       throw new IndexOutOfBoundsException(String.valueOf(idx)); 

      this.idx = idx<<2; 
      return this; 
     } 

     public int index(){ 
      return idx>>2; 
     } 

     public Idx shl32(){ 
      final int[] array=this.array; 
      int idx = this.idx; 

      array[idx]=array[++idx]; 
      array[idx]=array[++idx]; 
      array[idx]=array[++idx];     
      array[idx]=0; 

      return this; 
     } 

     public Idx shr32(){ 
      final int[] array=this.array; 
      int idx = this.idx+3; 

      array[idx]=array[--idx]; 
      array[idx]=array[--idx]; 
      array[idx]=array[--idx];     
      array[idx]=0; 
      return this; 
     } 
     public Idx or(Idx src){   
      final int[] array=this.array; 
      int idx = this.idx; 

      int idx2 = src.idx; 
      final int[] array2=src.array; 

      array[idx++]|=array2[idx2++]; 
      array[idx++]|=array2[idx2++]; 
      array[idx++]|=array2[idx2++]; 
      array[idx++]|=array2[idx2++]; 

      return this;    
     } 

     public Idx xor(Idx src){    
      final int[] array=this.array; 
      int idx = this.idx; 

      int idx2 = src.idx; 
      final int[] array2=src.array; 

      array[idx++]^=array2[idx2++]; 
      array[idx++]^=array2[idx2++]; 
      array[idx++]^=array2[idx2++]; 
      array[idx++]^=array2[idx2++]; 

      return this;    
     } 

     public Idx add(Idx src){    
      final int[] array=this.array; 
      int idx = this.idx+3; 

      final int[] array2=src.array; 
      int idx2 = src.idx+3; 


      long l =0; 

      l += array[idx]&mask; 
      l += array2[idx2--]&mask;   
      array[idx--]=(int)(l&mask); 
      l>>>=32; 


      l += array[idx]&mask; 
      l += array2[idx2--]&mask;   
      array[idx--]=(int)(l&mask); 
      l>>>=32; 

      l += array[idx]&mask; 
      l += array2[idx2--]&mask;   
      array[idx--]=(int)(l&mask); 
      l>>>=32; 

      l += array[idx]&mask; 
      l += array2[idx2--];    
      array[idx]=(int)(l&mask); 
//   l>>>=32; 

      return this;    
     } 

     public Idx set(long high, long low){ 
      final int[] array=this.array; 
      int idx = this.idx; 
      array[idx+0]=(int) ((high>>>32)&mask); 
      array[idx+1]=(int) ((high>>>0)&mask); 


      array[idx+2]=(int) ((low>>>32)&mask); 
      array[idx+3]=(int) ((low>>>0)&mask); 
      return this; 
     } 


     public long high(){ 
      final int[] array=this.array; 
      int idx = this.idx; 
      long res = (array[idx]&mask)<<32 | (array[idx+1]&mask); 
      return res; 
     } 

     public long low(){ 
      final int[] array=this.array; 
      int idx = this.idx; 
      long res = (array[idx+2]&mask)<<32 | (array[idx+3]&mask); 
      return res; 
     } 

     //ineffective but well 
     public String toString(){     
      return String.format("%016x-%016x", high(), low()); 
     } 
    } 

    public static void main(String[] args) { 
     Bitz bitz = Bitz.allocate(256); 
     Bitz.Idx idx = bitz.newIdx(0); 
     Bitz.Idx idx2 = bitz.newIdx(2); 

     System.out.println(idx.set(0, 0xf)); 
     System.out.println(idx2.set(0, Long.MIN_VALUE).xor(idx));  

     System.out.println(idx.set(0, Long.MAX_VALUE).add(idx2.set(0, 1))); 
     System.out.println("=="); 
     System.out.println(idx.add(idx));//can add itself 

     System.out.println(idx.shl32());//left 
     System.out.println(idx.shr32());//and right 
     System.out.println(idx.shl32());//back left 

     //w/ alloc 
     System.out.println(idx.add(bitz.newIdx(4).set(0, Long.MAX_VALUE))); 

     //self xor 
     System.out.println(idx.xor(idx)); 
     //random xor 

     System.out.println("===init random==="); 
     Random r = new Random(1112); 
     for (int i=0, s=bitz.size(); i<s; i++){ 
      idx.set(i).set(r.nextLong(), r.nextLong()); 
      System.out.println(idx); 
     } 
     Idx theXor = bitz.newIdx(0); 
     for (int i=1, s=bitz.size(); i<s; i++){   
      theXor.xor(idx.set(i)); 
     } 

     System.out.println("===XOR==="); 
     System.out.println(theXor); 
    } 
} 
1

对不起没有一个更好的答案。

一种方法可能是为两个长值创建包装器对象,并在考虑相关操作员的签名的同时实现所需的功能。还有BigInteger [从rlibby的答案更新],但它不提供所需的支持。

快乐编码。

+0

这就是我正在考虑的方法 – richs 2011-03-11 22:44:17

1

不再有数据类型比long(I已经登录这为具有128位浮点沿RFE)

可以创建具有4个32位int值的对象和相当支持这些操作容易。

1

您无法定义任何可以应用Java的内置按位运算符的新类型。

但是,您可以使用java.math.BigInteger吗? BigInteger定义了所有为整型类型定义的按位操作(作为方法)。这包括,例如,BigInteger.or(BigInteger)

1

或许BitSet对您有用。

它具有逻辑运算,我想如果考虑到它们的实用方法,转移不会很难实现。

+0

实际上,使用BitSet API实现shift *效率会很棘手。 – 2011-03-11 23:32:28

+0

@Stephen这是真的。 – corsiKa 2011-03-11 23:48:22

+0

@Stephen - 奇怪的是,右移_is_已经实现了,参见'BitSet.get(int,int)'。不过,由于某种原因,他们忽略了左移。 – jtahlborn 2011-03-12 01:11:32

3

三种可能性已经确定:

  • BitSet类提供一些你需要的操作,但没有“转移”方法。为了实现这个缺少方法,你需要做这样的事情:

    BitSet bits = new BitSet(128); 
    ... 
    // shift left by 32bits 
    for (int i = 0; i < 96; i++) { 
        bits.set(i, bits.get(i + 32)); 
    } 
    bits.set(96, 127, false); 
    
  • BigInteger类提供了所有的方法(或多或少),但由于BigInteger是一成不变的,它可能结果过度的对象创建速率......取决于你如何使用位集。 (另外还有一点shiftLeft(32)不会砍掉最左边位的问题...但你可以通过使用and索引128和更高掩盖了位处理这事。)

  • 如果性能是你的钥匙关注,实施具有4 int或2 long字段的自定义类可能会提供最佳性能。 (实际上这两者中更快的选择将取决于硬件平台,JVM等。我可能会选择long版本,因为它会更简单地编写代码,并且只在性能分析时尝试进一步优化这是一个潜在的有价值的活动。)

    此外,您可以设计API以完全按照您的要求(模仿Java语言的约束)行事。缺点是你必须实现和测试所有的东西,而且你会将魔法数字128硬编码到你的代码库中。

+0

即使在32位上,长度总是更好(mmx reg可以用来执行单一负载) – bestsss 2011-03-12 00:17:18

+0

@bestsss您假设x86/x86-64架构。 – 2011-03-12 07:13:53

+0

@Stephan,x86,x64有它的原生64寄存器,但即使是'小'处理器XScale,ARMv7也有64位寄存器来处理单个指令中的加载。当然,“always”的使用过于自由,因为不是所有的CPU都有可用的64位加载指令。 – bestsss 2011-03-12 09:44:53

0

Afaik,JVM只会将你编码的任何代码转换成32位块,不管你做什么。 JVM是32位。我认为甚至64位版本的JVM大部分都在32位块中进行处理。它当然应该保存内存......当JIT试图优化你创建的混乱时,你只会减慢你的代码。在C/C++等中,这么做没有意义,因为在最有可能使用的硬件中,它的32位或64位寄存器仍然会阻塞。即使是英特尔Xenon Phi(具有512位向量寄存器)也只是32和64位元素的集合。

如果你想实现类似的东西,你可以尝试在GLSL或OpenCL中做,如果你有GPU硬件可用的话。 2015年,Java Sumatra将作为Java 9的一部分发布,至少这是该计划。然后,您将能够将Java与GPU代码直接整合在一起。这是一个大问题,因此这个杰出的名字!