2011-03-11 44 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代碼直接整合在一起。這是一個大問題,因此這個傑出的名字!