Java отрицательный BigInteger toString

Кажется, у меня есть проблема с дополнением до двух с Java BigInteger. У меня есть 64-битное целое число, в котором только старший бит и второй старший бит установлены в 1, остальное равно 0.

В десятичном виде получается: -4611686018427387904.

Сторона Java моего приложения получает это десятичное число в виде строки и преобразует его в BigInteger следующим образом:

BigInteger bi = new BigInteger("-4611686018427387904", 10);

Затем ему необходимо отобразить это число как в двоичной, так и в шестнадцатеричной форме. Я пытался использовать:

String bin = bi.toString(2);
String hex = bi.toString(16);

но я получаю:

-100000000000000000000000000000000000000000000000000000000000000

-4000000000000000

тогда как я ожидаю получить:

1100000000000000000000000000000000000000000000000000000000000000

c000000000000000

Какие-нибудь советы?


person Noa    schedule 28.06.2011    source источник
comment
Если у вас есть 64-битное целое число со знаком, почему вы используете BigInteger, а не long?   -  person Jon Skeet    schedule 28.06.2011
comment
может быть больше 64   -  person Noa    schedule 28.06.2011
comment
Итак, вы хотите версию с дополнением 2s, но без фиксированного размера? Мне непонятно, как вы это представляете. Что вы ожидаете увидеть, например, для -1?   -  person Jon Skeet    schedule 28.06.2011


Ответы (5)


Существует метод BigInteger.toByteArray(), который возвращает представление BigInteger в виде дополнения до двух как byte[]. Все, что вам нужно, это напечатать этот массив в шестнадцатеричном или двоичном виде:

byte[] bs = bi.toByteArray();
for (byte b: bs) {
     System.out.print(String.format("%02X", 0xff & b));
}
person axtavt    schedule 28.06.2011
comment
это прекрасно работает, но я не могу заставить его работать в двоичном формате (никогда не был хорош с форматированием строк...) - person Noa; 28.06.2011

Число всегда умещается в 64 бита:

Если ваш номер всегда умещается в 64 бита, вы можете поместить его в длинное число, а затем напечатать биты/шестнадцатеричные цифры.

long l = bi.longValue();
String bin = Long.toBinaryString(l);
String hex = Long.toHexString(l);

System.out.println(bin);
System.out.println(hex);

Число может не всегда умещаться в 64 бита:

Если число не всегда умещается в 64-битном формате, вам придется решать его "вручную". Чтобы преобразовать число в представление дополнения до двух, вы делаете следующее:

  • Если число положительное, ничего не делать
  • If number is negative:
    • Convert it to its absolute value
    • Дополнить биты
    • Добавить 1

Для BigInteger преобразование выглядит следующим образом:

if (bi.compareTo(BigInteger.ZERO) < 0)
    bi = bi.abs().not().add(BigInteger.ONE);

Если вы напечатаете его с помощью bi.toString(2), вы все равно получите символ знака вместо ведущего 1. Это можно решить, просто добавив .replace('-', '1') к строке.

person aioobe    schedule 28.06.2011
comment
поэтому, чтобы получить шестнадцатеричное представление, мне нужно удалить знак минус и настроить первый шестнадцатеричный символ? - person Noa; 28.06.2011

Двоичное число 1100000000000000000000000000000000000000000000000000000000000000000 определенно является положительным числом, верно. Это равно 2^63 + 2^62. Я не понимаю, почему вы ожидаете, что отрицательное число станет положительным при преобразовании в основание 2 или основание 16.

Вы путаете базовое представление n с внутренним представлением чисел.

person Petar Ivanov    schedule 28.06.2011
comment
где - знак - это первый бит, который немного упрощает дополнение до двух. - person Joachim Sauer; 28.06.2011

Если число составляет 64 бита или меньше, то простой способ решить эту проблему — преобразовать его в long, а затем использовать Long.toHexString().

person Stephen C    schedule 28.06.2011

что ты имеешь в виду? Хочешь получить дополнение Two?

если вы имеете в виду это, может быть, я могу привести вам пример

import java.util.*;
public class TestBina{
static void printBinaryInt(int i){
System.out.println("int:"+i+",binary:");
System.out.print("  ");
for(int j=31;j>=0;j--)
   if(((1<<j)&i)!=0)
    System.out.print("1");
   else
    System.out.print("0");
  System.out.println();
 }
 public static void main(String [] args){
  Random rand = new Random();
  int i = rand.nextInt();
  int j = rand.nextInt();
  printBinaryInt(i);
  printBinaryInt(j);
  printBinaryInt(10);
  printBinaryInt(-10);
 }
}  
person user818767    schedule 28.06.2011