128-битная структура Java - PullRequest
       5

128-битная структура Java

6 голосов
/ 12 марта 2011

Есть ли способ создать 128-битный объект в Java, который может управляться битами так же, как long или int?Я хочу сделать 32-битные смены, и я хочу иметь возможность выполнять операции ИЛИ на всей 128-битной структуре.

Ответы [ 7 ]

4 голосов
/ 12 марта 2011

Здесь я представляю вам ... старую идею. Теперь он ужасно понижен (без улучшения кода, без ничего) до простой 128-битной штуковины, которая должна быть очень быстрой. То, что я действительно хочу, это основанный на ByteBuffer массив C, как Struct, но полностью пригодный для использования в Java.

Основная идея заключается в выделении более одного объекта одновременно и использовании указателя на массив. Таким образом, это значительно экономит память, а память выделяется в непрерывной области, поэтому меньше кеш-памяти пропускает (всегда хорошо).

Я провел небольшое тестирование (но код все еще не проверен). Он допускает базовые операции, такие как add, xor или set / get с 128-битными числами. К сожалению, применяется стандартное правило: меньше документации, чем ожидалось. Добавление дополнительного кода для дополнительных операций должно быть простым.

Вот код, посмотрите на метод main для некоторого использования. Ура!

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);
    }
}
3 голосов
/ 12 марта 2011

Три возможности были определены:

  • Класс BitSet предоставляет некоторые необходимые вам операции, но не метод "shift". Чтобы реализовать этот недостающий метод, вам нужно сделать что-то вроде этого:

    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 в свою кодовую базу.

2 голосов
/ 12 марта 2011

Нет больше типа данных, чем long (я зарегистрировал это как RFE вместе со 128-битной плавающей точкой;)

Вы можете создать объект с четырьмя 32-битными int значениями и довольно легко поддерживать эти операции.

1 голос
/ 12 марта 2011

Возможно, BitSet было бы полезно для вас.

В нем есть логические операции, и я думаю, что сдвиг не так уж сложно реализовать, учитывая их служебные методы.

1 голос
/ 12 марта 2011

Вы не можете определить какие-либо новые типы, к которым вы могли бы применить встроенные побитовые операторы Java.

Однако, вы могли бы просто использовать java.math.BigInteger?BigInteger определяет все побитовые операции, которые определены для целочисленных типов (как методы).Это включает, например, BigInteger.or(BigInteger).

1 голос
/ 12 марта 2011

номер

Извините, лучшего ответа нет.

Одним из подходов может быть создание объекта-обертки для двух длинных значений и реализация необходимых функций с учетом подписи соответствующих операторов. Существует также BigInteger [обновлено из ответа Рлибби], но он не обеспечивает необходимую поддержку.

Удачного кодирования.

0 голосов
/ 08 марта 2014

Afaik, JVM просто преобразует все, что вы кодируете, в 32-битные блоки, что бы вы ни делали.JVM является 32-битной.Я думаю, что даже 64-битная версия JVM в основном обрабатывается в 32-битных блоках.Это определенно должно сохранить память ... Вы просто собираетесь замедлить ваш код, поскольку JIT пытается оптимизировать беспорядок, который вы создаете.В C / C ++ и т. Д. Нет никакого смысла делать это, так как у вас все равно будет сопротивление из-за того, что это 32- или 64-битные регистры на оборудовании, которое вы, скорее всего, используете.Даже Intel Xenon Phi (имеет 512-битные векторные регистры) - это просто наборы 32- и 64-битных элементов.

Если вы хотите реализовать что-то подобное, вы можете попробовать сделать это в GLSL или OpenCL, если у вас есть графический процессороборудование доступно.В 2015 году Java Sumatra будет выпущена как часть Java 9, по крайней мере, это план.Тогда у вас будет возможность интегрировать Java с кодом GPU из коробки.Это большое дело, отсюда и прославленное имя!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...