Как преобразовать java BigDecimal в обычный массив байтов (не дополнение 2)

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

Таким образом, что-то вроде 10 станет байтом 0x0a, то есть -> 00001010.

[Обновление] Согласно комментарию, я попробовал это

public void testBinary()
{
    BigDecimal test = new BigDecimal(35116031);
    BigInteger theInt = test.unscaledValue();
    byte[] arr = theInt.toByteArray();
    System.out.println(getCounterVal(arr, new BigInteger("256")));
}
public BigInteger getCounterVal(byte[] arr, BigInteger multiplier)
{
    BigInteger counter = BigInteger.ZERO;
    for(int i = (arr.length - 1); i >=0; i--)
    {
        int b = arr[i];
        //int val = (int) b & 0xFF;
        BigInteger augend = BigInteger.valueOf(b);
        counter = counter.add(augend.multiply(multiplier.pow(i)));
    }
    return counter;
}

Выходное значение, которое я получил, было -19720446. И с //int val = (int) b & 0xFF; раскомментировал и использовал как augend, я получил значение 4292024066

[Update2] Вот тест, который я провел, и он работает. Не уверен, что это без ошибок, но выглядит нормально.

@Test
public void bigIntegerToArray()
{
    BigInteger bigInt = new BigInteger("35116444");
    byte[] array = bigInt.toByteArray();
    if (array[0] == 0)
    {
        byte[] tmp = new byte[array.length - 1];
        System.arraycopy(array, 1, tmp, 0, tmp.length);
        array = tmp;
    }

    BigInteger derived = BigInteger.ZERO;
    BigInteger twofiftysix = new BigInteger("256");
    int j = 0;
    for (int i = array.length - 1; i >= 0; i--)
    {
        int val = (int) array[i] & 0xFF;
        BigInteger addend = BigInteger.valueOf(val);
        BigInteger multiplier = twofiftysix.pow(j);
        addend = addend.multiply(multiplier);
        derived = derived.add(addend);
        j++;
    }

    Assert.assertEquals(bigInt, derived);
}

person Abe    schedule 29.05.2011    source источник
comment
Ваш цикл в getCounterVal кажется обратным.   -  person Hot Licks    schedule 30.05.2011
comment
Пробовал цикл в обоих направлениях и получил неожиданные значения int.   -  person Abe    schedule 30.05.2011
comment
Также обратите внимание, что вам нужна закомментированная строка, поскольку байт подписан и в противном случае будет расширен знаком.   -  person Hot Licks    schedule 30.05.2011


Ответы (4)


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

то есть 10 - это 00001010 в знаковом и беззнаковом представлении.

Чтобы получить байты из BigDecimal или BigInteger, вы можете использовать предоставляемые им методы.

BigDecimal test = new BigDecimal(35116031);
BigInteger theInt = test.unscaledValue();
byte[] arr = theInt.toByteArray();
System.out.println(Arrays.toString(arr));

BigInteger bi2 = new BigInteger(arr);
BigDecimal bd2 = new BigDecimal(bi2, 0);
System.out.println(bd2);

отпечатки

[2, 23, -45, -1]
35116031

Байты правильные и воспроизводят одно и то же значение.

Существует ошибка в том, как вы перестраиваете свой BigInteger. Вы предполагаете, что сериализация байтов имеет обратный порядок байтов, тогда как Java обычно использует обратный порядок байтов http://en.wikipedia.org/wiki/Endianness

person Peter Lawrey    schedule 29.05.2011
comment
Я предоставил обновление для q, пожалуйста, проверьте и дайте знать. Спасибо за ответы! - person Abe; 29.05.2011
comment
@Abe, вам нужно проверить порядок байтов вашего решения. - person Peter Lawrey; 30.05.2011
comment
Не работает для значений с плавающей запятой (например: 25,53 ---> 2553 будет результатом) - person Martijn Courteaux; 02.11.2011
comment
Для поддержки значений с плавающей запятой вы также должны сохранить масштаб и восстановить его при реконструкции. BigDecimal bd2 = новый BigDecimal(bi2, шкала); - person vahapt; 04.01.2016

Попробуйте разбить число на байты, разделив на 256 на каждой итерации и используя остаток, и поместите все эти байты в массив.

person Daniel    schedule 29.05.2011
comment
Есть ли более простой способ сделать это? - person Abe; 29.05.2011
comment
Это необычная задача, поэтому я не верю. На самом деле то, что я описал, не должно быть слишком сложным. - person Daniel; 29.05.2011

бит знака в 2-compliment для положительных чисел равен 0

поэтому знак или без знака не имеет значения для положительных чисел

person ratchet freak    schedule 29.05.2011

Если значение меньше размера длинного, используйте longValue, а затем разбейте длинное на байты. Если значение больше длинного, то, вероятно, вам нужно использовать итеративный подход, многократно деля число на 256, принимая остаток в качестве следующего байта, а затем повторяя, пока не получите ноль. Байты будут генерироваться справа налево. Числа со знаком требуют размышлений (для получения результатов с дополнением до 2), но не намного сложнее.

person Hot Licks    schedule 29.05.2011