ceran ceran - 1 month ago 5
Scala Question

Extract Longs from ByteBuffer (Java/Scala)

I'm constructing

BigInt
numbers that consist of two
Long
s each in the following way:

val msb = -1L // some arbitrary long value, can be anything between Long.Min/MaxValue
val lsb = 25L // a second arbitrary long value

val bb = ByteBuffer
.allocate(17)
.put(0.toByte) // 1 byte
.putLong(msb) // 8 bytes
.putLong(lsb) // 8 bytes

val number = BigInt(bb.array) // in this case: 340282366920938463444927863358058659865


The reason I'm adding another 0-
Byte
at the front is to guarantee that the result is a positive number. Otherwise, the resulting
BigInt
could be negative due to two's complement. An algorithm that is called afterwards expects numbers greater or equal than zero.

So far, so good.

I'm having trouble with reversing this whole process - transforming the
BigInt
back to two
Long
s (exactly the two values that were used as the input). I can't just do the following:

val arr = number.toByteArray
val bb = ByteBuffer.wrap(arr)
val ignore = bb.getByte
val msb = bb.getLong
val lsb = bb.getLong


Imagine the
BigInt
number is e.g. 3. Then
.toByteArray
would result in an Array of size 1, not 16 (or 17), and therefore the calls to
getLong
would cause a
BufferUnderflowException
.

What's the easiest way to solve this problem? I tried several ways to manually fill up the buffer until there are 16 bytes available, but since this "padding" must correctly take the two's complement of the two numbers into account, I wasn't succesful.

Answer

Modulo operation can be helpful here:

....
val number = BigInt(bb.array) // in this case: 340282366920938463444927863358058659865

val modulo = BigInt(2).pow(64)
val lsb2 = (number / modulo).toLong     //25
val msb2 = (number.mod(modulo)).toLong  //-1
Comments