从ByteBuffer中提取Longs(Java/Scala)

cer*_*ran 7 java arrays bytebuffer scala

我正在以下列方式构建BigInt由两个Longs 组成的数字:

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
Run Code Online (Sandbox Code Playgroud)

Byte在前面添加另一个0-的原因是为了保证结果是正数.否则,由于两个补码,结果BigInt 可能是负的.之后调用的算法期望大于或等于零的数字.

到现在为止还挺好.

我在翻转整个过程时遇到了麻烦 - 将BigInt后面的内容转换为两个Long(确切地说是用作输入的两个值).我不能只做以下事情:

val arr = number.toByteArray
val bb = ByteBuffer.wrap(arr)
val ignore = bb.getByte
val msb = bb.getLong
val lsb = bb.getLong
Run Code Online (Sandbox Code Playgroud)

想象一下这个BigInt数字是例如3.然后.toByteArray会产生一个大小为1而不是16(或17)的数组,因此调用getLong会导致a BufferUnderflowException.

解决这个问题最简单的方法是什么?我尝试了几种方法来手动填充缓冲区,直到有16个字节可用,但由于这个"填充"必须正确地考虑两个数字的两个补码,我没有成功.

Pio*_*zke 5

模数运算在这里很有帮助:

....
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
Run Code Online (Sandbox Code Playgroud)