Как выполнить преобразование без знака в подписанное в Java?

Скажем, я прочитал эти байты: «6F D4 06 40» с устройства ввода. Число представляет собой значение долготы в формате MilliArcSeconds. Старший бит (0x80000000) в основном всегда равен нулю и игнорируется для этого вопроса.

Я могу легко преобразовать байты в целое число без знака: 1876166208.

Но как мне преобразовать это беззнаковое значение в его окончательную форму 31-битного целого числа со знаком?

Пока все, что я придумал, это:

  1. если значение & 0x40000000, то оно на самом деле отрицательное, его нужно преобразовать
  2. Если он отрицательный, удалите верхний бит и сделайте что-нибудь с оставшимися битами...

Итак, я могу сказать, является ли это отрицательным числом, но чтобы узнать, какое значение имеет отрицательное число, мне нужно что-то сделать с оставшимися битами — комплимент единице? Как мне это сделать в Java?

Другой способ поставить вопрос: как мне преобразовать целое число без знака в 31-битное целое число со знаком в Java?

Спасибо!


person Brad Hein    schedule 14.10.2010    source источник
comment
Я думаю, что неправильно понял ваш вопрос в своем ответе. Можете ли вы сказать, каким должно быть значение целого числа со знаком, исходя из вашего примера ввода? Ты никогда этого не говорил.   -  person Mark Peters    schedule 14.10.2010
comment
Вход: 6F D3 FD 45. Выход: приблизительно -75,366465. Я говорю приблизительный, потому что я нашел место и оставался там, чтобы собирать данные и в то же время измерял местоположение с помощью GPS. Таким образом, долгота выше (-75,366465) должна быть близкой, но, вероятно, не совсем той же величиной, что и приведенные выше шестнадцатеричные байты, преобразованные в целое число со знаком (и выполнено преобразование MAS в градусы). Я пытаюсь найти способ перейти от шестнадцатеричных байтов к целочисленному со знаком с помощью Java   -  person Brad Hein    schedule 15.10.2010
comment
MAS в Градусы: разделить на 3 600 000.   -  person Brad Hein    schedule 15.10.2010
comment
Приближаемся... Фактическое чтение с удаленным отрицательным битом: 2F D3 FD 45... сравните это с ожидаемым значением MAS -75,366465 для 10 2C 00 EA... Первые 22 бита совпадают, если я переверну 1 на 0 и 0 на 1 (исключающее ИЛИ). Я думаю, что это может быть хитростью - нужно перевернуть все биты... Я могу сделать это с помощью XOR...   -  person Brad Hein    schedule 15.10.2010
comment
@Марк, ты прав. Мои извенения.   -  person Brad Hein    schedule 15.10.2010


Ответы (2)


Ответ зависит от того, что должны представлять младшие 31 бит вашего ввода.

int input = 0x6FD40640 & 0x7FFFFFFF; //strip top bit; only here for clarity

Беззнаковый ввод: 0x6FD40640 == 1876166208

Дополнение до двух (желаемый результат: -271317440)

Целое число в дополнении до двух — это целое число, в котором -1 имеет все установленные биты, а меньшие отрицательные числа отсчитываются оттуда. Первый бит по-прежнему действует как бит знака.

1000 -> -8
1001 -> -7
...
1110 -> -2
1111 -> -1
0000 ->  0
0001 ->  1

Если младшие 31 бит представляют целое число с дополнением до двух, то я думаю, что вы должны просто сделать это:

input = (input << 1) >> 1;

Это связано с тем, что Java хранит целые числа в дополнении до двух внутри: все, что мы делаем, это сдвигаем влево, а затем сдвигаем назад вправо (со знаком), так что бит знака берется, и целое число переходит от 31 бита к 32 битам.

Дополнение до единицы (желаемый результат: -802424384)

Представление числа в дополнении до единицы — это представление, в котором первый бит является выделенным битом знака, а остальные биты представляют величину. Младшие биты -100 будут такими же, как младшие биты 100:

 1111 -> -7
 1110 -> -6
 ...
 1001 -> -1
 1000 -> -0 (anomoly)
 0000 ->  0
 0001 ->  1

Если младшие 31 бит представляют дополнение до единицы целое число (то есть знаковый бит, за которым следуют 30 бит, представляющие беззнаковую величину), то вам необходимо преобразовать его в дополнение до двух, чтобы Java правильно извлек значение. . Для этого вам просто нужно извлечь младшие 30 бит и умножить на -1:

if ( input & 0x40000000 ) {
   input = (input & 0x3FFFFFFF) * -1;
}

В комментариях к вопросу вы сказали, что после преобразования в градусы (деления на 3600000) вы получаете около -75,36. Когда я делю -271317440 на 3600000, я получаю -75,36595555555556, поэтому я предполагаю, что ваш формат ввода - дополнение до двух, поэтому мой первый и первоначальный ответ был правильным.

person Mark Peters    schedule 14.10.2010
comment
Похоже, дело пойдет. Не уверен, что & 0x7FFFFFFF необходим. - person Armand; 14.10.2010
comment
Кажется, что &7ffffffff и сдвиг влево/вправо делают одно и то же (удаляют крайний левый верхний бит)? Я работаю над получением некоторых образцов данных, чтобы мы могли проверить это. - person Brad Hein; 14.10.2010
comment
@Alison: нет, это было просто для того, чтобы продемонстрировать, что ввод был только младшим 31 битом, а старший бит не имеет значения. Вторая строка — это то, что я пытался показать, но Брэд не подтвердил, является ли это желаемым результатом или нет. - person Mark Peters; 14.10.2010
comment
@Brad: просто &7FFFFFFF просто очистит верхний бит. Это смещается влево, но смещается вправо в расширенной знаковой манере. Другими словами, он заполняет первый бит вторым битом. Но опять же, мне нужно увидеть, какой у вас желаемый результат... Я не знаю, что должны представлять 31 младший бит. - person Mark Peters; 14.10.2010
comment
Почему за этот ответ проголосовали? Это вообще не решает вопрос. Пожалуйста, перечитайте вопрос! - person Brad Hein; 15.10.2010

Чтение целого числа без знака как знакового — это вопрос определения того, установлен ли самый значащий бит (отрицательный флаг), и если да, то инвертировать все биты числа (таким образом очищая старший значащий бит и переключая число на его отрицательное представление. При выполнении вышеупомянутого процесса вы также должны учитывать тот факт, что результирующее число является отрицательным.

// Convert the hex bytes to an unsigned integer
long MAS = Integer.ValueOf("6F D4 06 40".replace (" ",""),16);
boolean isLongitudeNegative = false;

// Is the negative-bit set? If so, strip it and toggle all bits.
if (MAS & 0x40000000 > 0) {
    // then it's negative, so strip the negative bit and flip all the other bits
    MAS ^= 0xFFFFFFFF;
    // Throw away the unused bit.
    MAS &= 0x7FFFFFFF;
    isLongitudeNegative = true;
}

// Now convert from MAS to degrees minutes seconds
String DMS = convertMASToDMS(isLongitudeNegative,MAS);
person Brad Hein    schedule 15.10.2010
comment
Извините за порывы. Этот ответ в конечном итоге помог вашим требованиям? Если это так, не стесняйтесь принять это. Единственное предложение состоит в том, что вы можете найти MAS = ~MAS более понятным способом переключения битов MAS. Итак, учитывая это решение, я предполагаю, что младшие 31 бит ввода представляют собой 31-битное целое число, и вы пытаетесь извлечь это значение? Это проблема, которую вы пытались решить? - person Mark Peters; 16.10.2010
comment
Проверьте мой ответ еще раз. Я почти уверен, что мой первоначальный ответ был правильным. Когда я применяю свое преобразование к вашему входному образцу, а затем делю на 3600000, я получаю -75,369555, что является вашим ожидаемым результатом. Когда я делаю ваше преобразование, я получаю -222, что не соответствует действительности. - person Mark Peters; 16.10.2010