2016-11-16 1 views
3

Когда яПочему я получаю значение обратно из Long.parseUnsignedLong, когда я не должен быть

Long.parseUnsignedLong("FBD626CC4961A4FC", 16) 

я вернусь -300009666327239428

Что кажется неправильным, так как значение без знака длиной в соответствии с этот ответ https://stackoverflow.com/a/2550367/1754020 заключается в том, что диапазон всегда положительный.

Чтобы получить правильное число от этого значения HEX я

BigInteger value = new BigInteger("FBD626CC4961A4FC", 16); 

При печати значения печатает правильное значение. но если я сделаю value.longValue()

еще раз я получаю то же самое -300009666327239428 это из числа слишком большого и переполненного?

+3

Печать 'Long.MAX_VALUE' и сравнить. Да, он слишком велик, чтобы вписаться в «длинный». – Tunaki

+0

так что это не исключение? –

+1

[Документация] (https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html#parseUnsignedLong-java.lang.String-int-) утверждает, что он должен бросить ' NumberFormatException' if "Значение, представленное строкой, больше, чем наибольшее значение unsigned long, 2^64-1." Извините, но у меня нет ответа. – tsm

ответ

5

Java 8 (немного) поддержка неподписанные longs, однако вы не можете просто распечатать их напрямую. Это даст вам результат, который вы видели.

Если у вас есть беззнаковое длинное

Long number = Long.parseUnsignedLong("FBD626CC4961A4FC", 16); 

вы можете получить правильное представление строки с помощью функции

String numberToPrint = Long.toUnsignedString(number); 

Если теперь напечатать numberToPrint вы получаете

18146734407382312188 

Чтобы быть более точно, ваш номер по-прежнему будет регулярным подписалlong, поэтому он отображает переполнение, если печатается напрямую. Однако существуют новые статические функции, которые будут обрабатывать значение, как если бы оно было без знака, например, Long.toUnsignedString(long x) или Long.compareUnsigned(long x, long y).

+0

Это очень хороший вопрос о 'Long.toUnsignedString (number)' – Andremoniy

1

Да, он переполняется, когда вы пытаетесь его распечатать, так как он преобразуется в Java long. Чтобы понять, почему давайте возьмем log2 вашего значения dec.

Первое, оригинальное значение 18146734407382312188. Это log2 ~ 63.9763437545.

Во-вторых, посмотрите на documentation: в java long type представлены значения -2^63 и максимальное значение 2^63-1.

Таким образом, ваше значение, очевидно, больше чем 2^63-1, следовательно, он переполняется:

-2^63 + (18146734407382312188 - 2^63 + 1) = -300009666327239428 

Но @Keiwan блестяще говорил, вы все еще можете напечатать нужное значение с помощью Long.toUnsignedString(number);

1

Внутренне без знака и подписанные числа представлены одинаково, т. е. 8 байтов в случае длинного. Разница только в том, как интерпретируется бит «знака», т. Е. Если вы сделаете то же самое в программе на C/C++ и сохраните свое значение в uint64_t, а затем нарисуйте/сопоставьте его с назначенным int64_t, вы получите тот же результат.

Поскольку максимальное значение 8 байтов или 64 бита может содержать 2^64-1, это жесткое ограничение для таких чисел.Кроме того, Java не поддерживает прямую поддержку беззнаковых чисел, и поэтому единственный способ сохранить unsigned long в long - это разрешить значение, которое выше, чем подписанное Long.MAX_VALUE. Фактически, Java не знает, будет ли строка/шестнадцатеричный код, который вы читаете, представлять собой подписанный или unsigned long, поэтому вам следует предоставить эту интерпретацию либо путем преобразования обратно в строку, либо с использованием более крупного типа данных, такого как BigInteger ,

2

Шестнадцатиричное число "FBD626CC4961A4FC", преобразованное в десятичное значение, равно точно 18146734407382312188. Это число действительно больше, чем максимально возможное long, определяется как Long.MAX_VALUE и которая равна 2 -1, или 9223372036854775807:

System.out.println(new BigInteger("FBD626CC4961A4FC", 16)); // 18146734407382312188 
System.out.println(Long.MAX_VALUE);       // 9223372036854775807 

Таким образом, это нормально, что вы получите обратно отрицательное число.

Вы не исключение, так как это именно цель этих новых *Unsigned* методов, добавленных в Java 8, чтобы дать возможность обрабатывать неподписанных лонги (как compareUnsigned или divideUnsigned). Так как тип long в Java is still unsigned, эти методы работают, понимая отрицательные значения как значения, превышающие MAX_VALUE: он имитирует беззнаковый длинный. parseUnsignedLong говорит:

Целое число без знака отображает значения, как правило, связанные с отрицательными числами до положительных чисел больше, чем MAX_VALUE.

При печати long, который был результатом parseUnsignedLong, и он отрицательный, все это означает, что значение больше чем максимальное длинное значение, как определено в языке, но методы принятия неподписанные лонги как параметр будет правильно интерпретировать эти значения, как если бы они были больше максимального значения. Таким образом, вместо того, чтобы печатать его напрямую, если вы передадите этот номер toUnsignedString, вы получите правильный вывод, like shown in this other answer. Не все эти методы новы для Java 8, например, toHexString также интерпретирует данный long как unsigned long в базе 16, а печать Long.toHexString(Long.parseUnsignedLong("FBD626CC4961A4FC", 16)) вернет вам правую шестнадцатеричную строку.

parseUnsignedLong сгенерирует исключение только тогда, когда значение не может быть представлено как беззнаковое долго, то есть не ряд вообще, или больше, чем 2 -1 (а не 2 -1, который является максимальным значение для подписанного долго).

Смежные вопросы