2011-03-11 14 views
5

¿Hay alguna manera de crear un objeto de 128 bits en java, que se pueda manipular en bits de la misma forma que un largo o int? Quiero hacer cambios de 32 bits y quiero poder hacer un poco de operación O en toda la estructura de 128 bits.java estructura de bit 128 maninpulation

Respuesta

2

Aquí les presento ... una vieja idea. Ahora está muy degradado (sin potenciador de código, sin nada) a simple thingie de 128 bits que debería ser súper rápido, sin embargo. Lo que realmente quiero es una matriz basada en ByteBuffer de C alike Struct pero totalmente utilizable en java.

La idea principal es asignar más de un solo objeto a la vez y usar un puntero a la matriz. Por lo tanto, conserva mucho la memoria y la memoria se asigna en un área continua, por lo que pierde menos memoria caché (siempre es bueno).

Realicé algunas pruebas moderadas (pero el código aún no se ha probado). Permite operaciones básicas como add, xor o set/get con números de 128 bits. La regla estándar: menos documentación de la esperada aplicada desafortunadamente. Agregar código adicional para operaciones adicionales debe ser sencillo.

Aquí está el código, mira el método principal para cierto uso. ¡Aclamaciones!

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

En este momento no hay una respuesta mejor.

Un enfoque puede ser crear un objeto envoltorio para dos valores largos e implementar la funcionalidad requerida teniendo en cuenta la firma de los operadores relevantes. También hay BigInteger [actualizado desde la respuesta de rlibby], pero no proporciona el soporte requerido.

Happy coding.

+0

este fue el enfoque que también estaba considerando – richs

1

No hay ningún tipo de datos más largo que long (I han registrado esto como una RFE junto con un punto flotante de 128 bits;)

Puede crear un objeto con cuatro int valores de 32 bits y apoyar estas operaciones bastante fácilmente.

1

No puede definir ningún tipo nuevo al que pueda aplicar los operadores bit a bit integrados de Java.

Sin embargo, ¿podría simplemente usar java.math.BigInteger? BigInteger define todas las operaciones de bits definidas para tipos integrales (como métodos). Esto incluye, por ejemplo, BigInteger.or(BigInteger).

1

Quizás BitSet te sea útil.

Tiene las operaciones lógicas, y me imagino que el cambio no sería tan difícil de implementar dado sus métodos de utilidad.

+0

En realidad, la implementación del cambio * eficientemente * usando la API 'BitSet' sería complicado. –

+0

@Stephen Eso es verdad. – corsiKa

+0

@Stephen: por extraño que parezca, el cambio a la derecha ya está implementado, vea 'BitSet.get (int, int)'. por alguna razón, sin embargo, descuidaron el turno de la izquierda. – jtahlborn

3

tres posibilidades se han identificado:

  • La clase BitSet ofrece algunas de las operaciones que necesita, pero ningún método "cambio". Para poner en práctica este método faltante, que había necesidad de hacer algo como esto:

    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); 
    
  • La clase BigInteger proporciona todos los métodos (más o menos), pero desde BigInteger es inmutable, que podría resultado en una tasa de creación de objeto excesiva ... dependiendo de cómo use los conjuntos de bits. (También existe el problema de que shiftLeft(32) no va a cortar los bits de la izquierda ... pero se puede hacer frente a esto mediante el uso and para enmascarar los bits en el índice 128 y superior.)

  • si el rendimiento es la clave preocupación, la implementación de una clase personalizada con 4 int o 2 long probablemente dará mejor rendimiento. (Que en realidad es la opción más rápida de las dos dependerá de la plataforma de hardware, la JVM, etc. Probablemente elegiría la versión long porque sería más simple codificar ... y solo trataría de optimizar aún más si los perfiles indicaban que fue una actividad potencialmente valiosa).

    Además, puede diseñar las API para que se comporten exactamente como lo requiera (módulo de las restricciones del lenguaje Java). La desventaja es que tienes que implementar y probar todo, y estarás cableando el número mágico 128 en tu código base.

+0

siempre es mejor incluso en 32 bits (el registro mmx se puede usar para realizar una sola carga) – bestsss

+0

@bestsss asume una arquitectura x86/x86-64. –

+0

@Stephan, x86, x64 tiene sus 64 registros nativos, pero incluso los procesadores 'pequeños' XScale, ARMv7 tienen registros de 64 bits para manejar la carga en una sola instrucción.Ciertamente, "siempre" se utiliza con demasiada frecuencia, ya que no todas las CPU tendrían instrucciones útiles de carga de 64 bits. – bestsss

0

Afaik, la JVM simplemente convertirá todo lo que codifique en trozos de 32 bits haga lo que haga. JVM es de 32 bits. Creo que incluso la versión de 64 bits de JVM procesa en gran medida en fragmentos de 32 bits. Sin duda, debería conservar la memoria ... Simplemente vas a ralentizar tu código a medida que el JIT intenta optimizar el desastre que creas. En C/C++, etc. no tiene sentido hacer esto tampoco, ya que aún tendrás la impedancia del hecho de que son registros de 32 o 64 bits en el hardware que probablemente uses. Incluso Intel Xenon Phi (tiene registros vectoriales de 512bit) es solo un conjunto de elementos de 32 y 64 bits.

Si desea implementar algo así, puede intentar hacerlo en GLSL u OpenCL si tiene hardware de GPU disponible. En 2015, Java Sumatra se lanzará como parte de Java 9, al menos ese es el plan. Luego, tendrá la capacidad de integrar java con el código GPU de fábrica. Eso ES un gran problema, ¡de ahí el nombre ilustre!

Cuestiones relacionadas