Ошибка битовых операций Java (преобразовать в байт и преобразовать обратно)

Я пытаюсь преобразовать дату рождения (три целых числа) в байты и преобразовать ее обратно, но у меня возникла проблема. Я должен преобразовать его с помощью битовых операций и отправить данные через многоадресный сервер, получить их и вернуться к int. Сервер работает нормально, но битовые операции для меня сложны. Что не так с кодом:

Конвертировать:

      int D=12; 
      int M=9; 
      int Y=1983;
      short DMY=0; 
      DMY = (short)(DMY | (D << 19));
      DMY = (short)(DMY | (M << 15));
      DMY = (short)(DMY | Y); 
      byte[] data = new byte[3];
      data[0] = (byte)(DMY >>> 8 );
      data[1] = (byte)(DMY >>> 16 );
      data[2] = (byte)(DMY & 0xffff);

Преобразовать обратно:

           byte[] rec_data = new byte[3];
           rec_data = dp.getData();
           short Rec_dmy;


           Rec_dmy = (short)(rec_data[0] & 0xff);
           Rec_dmy = (short) (Rec_dmy << 8);
           Rec_dmy = (short)(Rec_dmy | (rec_data[1] & 0xff));
           Rec_dmy = (short) (Rec_dmy << 8);
           Rec_dmy = (short)(Rec_dmy | (rec_data[2] & 0xffff));

           byte tmp = (byte) ((Rec_dmy  >>> 19) & 0x1F);
           byte tmp2 = (byte) ((Rec_dmy >>> 15) & 0x1FF);
           byte tmp3 = (byte) (Rec_dmy & 0x7F);       

            System.out.println(tmp);
            System.out.println(tmp2);
            System.out.println(tmp3);

Println дает следующий ответ: 31 -1 63

Это не оригинал 12 9 1983


person user1528100    schedule 25.08.2012    source источник
comment
Есть ли какая-то особая причина, по которой вы делаете это вручную?   -  person obataku    schedule 25.08.2012


Ответы (3)


Шорты могут содержать только 16 бит; вы пытаетесь упаковать больше, чем это (например, сдвиг дня влево на 19, что приведет к нулевому значению после приведения к шорту). Вам нужно использовать int или long для хранения всех полей.

Действительно, у вас есть несколько вещей, происходящих с битовыми операциями, которые неверны.

Мое предложение состояло бы в том, чтобы отказаться от битовых операций и просто отправить день, месяц и год в виде отдельных полей: по одному байту для каждого дня и месяца и два (коротких) для года. Это занимает 4 байта (только один дополнительный байт), но требует гораздо меньше возни, чтобы все получилось правильно.

person nneonneo    schedule 25.08.2012
comment
Сдвиг на 19 не смещает его полностью из short, поскольку тип выражения равен int, а расстояние сдвига вычисляется равным 19 & 31. Он теряет данные только при возврате к short. - person obataku; 25.08.2012
comment
Я думаю, я имел в виду это в смысле смещения за пределы жизнеспособного диапазона короткого замыкания (т. Е. Сдвига так, чтобы младшие 16 бит были равны нулю). Я уточню, что я имею в виду. - person nneonneo; 25.08.2012

Это непросто, но вы должны работать систематически, чтобы гарантировать, что ваши операции не а) не потеряют информацию б) не декодируют обратное тому, как вы кодировали.

int D = 12;
int M = 9;
int Y = 1983;
int DMY = (D << 19) | (M << 15) | Y;
byte[] data = new byte[3];
data[0] = (byte) (DMY >>> 16);
data[1] = (byte) (DMY >>> 8);
data[2] = (byte) DMY;

int DMY2 = ((data[0]&0xFF) << 16) | ((data[1]&0xFF) << 8) | (data[2]&0xFF);
int D2 = DMY2 >>> 19;          // no mask required
int M2 = (DMY2 >>> 15) & 0x0F; // 4 bits mask
int Y2 = DMY2 & 0x7FFF;        // 15 bit mask
System.out.println(D2 + "/" + M2 + "/" + Y2);

отпечатки

12/9/1983
person Peter Lawrey    schedule 25.08.2012

Во-первых, вам нужно как минимум 14 бит для представления года с максимальным значением 9999 из-за 2^14 > 9999 && 2 ^ 13 < 9999. И наименьшее количество бит для месяца - 4 (максимум 12), день - 5 (максимум 31). Таким образом, вы можете использовать короткий int (16 бит) для представления года и байта (8 бит) для каждого дня и месяца. Таким образом, вы получаете 32-битный int.

public int encoded(short year, byte month, byte day){
    int data =0;
    data = year & 0xFFFF;
    data =(data << 8)|(month & 0xFF)
    data =(data << 8)|(day & 0xFF)
    return data;
}

public void decode(int data){
    int day = data & 0xFF;
    int month = (data >> 8) & 0xFF;
    int year = (data >> 16) & 0xFFFF;
}
person George    schedule 25.08.2012
comment
За исключением того, что он использует 14 бит для года, 4 для месяца и 5 для дня! Его проблема в том, что битовая манипуляция неверна. - person nneonneo; 25.08.2012
comment
я изменил шорты на длинные, но все еще нет правильного ответа. nneonneo, в чем проблема с моими битовыми операциями? - person user1528100; 25.08.2012
comment
@ user1528100, вы использовали 13 бит для дня, 4 бита для месяца и оставшиеся 15 бит для года. Прежде всего, короткого для DMY недостаточно, вы должны использовать хотя бы int. Во-вторых, вы должны прекратить явно преобразовывать int в short. После этого вы затем преобразуете массив DMY в массив из трех байтов, чего может быть достаточно, и, что еще хуже, то, как вы конвертируете DMY в массив байтов, приводит к потере ваших данных. Это проблема. - person George; 25.08.2012