繁体   English   中英

Java中无符号长整数,使用BigInteger进行算术运算,但BigInteger.toByteArray返回14个字节而不是8个字节

[英]unsigned long in java, using BigInteger for arithmetics, but BigInteger.toByteArray returns 14 bytes instead of 8

我有以下C代码,其ID喜欢移植到Java

unsigned long long* data=(unsigned long long*)pBuffer; // file data
unsigned long long crypt = 0x0000;
unsigned long long next_crypt;
unsigned int len = size >> 3;

for(unsigned int i=0; i<len;i++) {
        next_crypt = crypt+data[i]-0xCAFEBABE;      
        data[i] = ((data[i]<<0x1d)|(data[i]>>0x23))+0xCAFEBABE;
        data[i] =  (data[i]<<0x0e)|(data[i]>>0x32);
        data[i] = data[i] - crypt;
        crypt = next_crypt;     

    }

我试图使用long将其移植到java,但是这将导致负值。 因此我切换到biginteger,因为我必须做算术(移位等)。

我使用BigInteger获得了所需的64位无符号长值,但是当我想将其转换为字节(BigInteger.toByteArray)时,它的长度为14个字节,而不再是8个字节-因此,我无法再修改数组/文件。 我尝试使用toLongValue(),但数据不正确。

谢谢

您的C代码依赖于从unsigned long long的高位端移出的位。 (通过另一个移位将它们旋转到另一端。)BigInteger是任意精度的,因此没有端点,因此,左移位的位永远不会移位。

您可以按位构造一个64位BigInteger AND掩码,并在向左移动后对其进行AND运算。 这是一个直观的解决方案。

您也可以简单地忽略高位字节。

byte[] bar = foo.toByteArray();
if (bar.length > 8) {
    bar = System.arrayCopy(bar, bar.length - 8, new byte[8], 0, 8);
}

如果len大,则此简单的解决方案将浪费内存。

在任何情况下,都有一个更合理,性能更高的解决方案。 Java的带符号整数类型都保证具有二进制补码语义。 具有二进制补码整数和无符号整数的算术的位语义是相同的-区别仅在于值的解释! 因此,只需使用原始的C代码(用Java的long代替),最后按您的方式解释它们。

byte[] longToByteArray(long x) {
    byte[] array = new byte[8];
    for (int i = 7; i >= 0; i--) {
        array[i] = (byte)x;
        x >>>= 8;
    }
}

顺便说一句,请确保将C代码中的>>运算符替换为Java的>>>运算符。

关于Java的好处是,它保证是二进制补码,因此,如果您使用>>>而不是>>并避免%和/和不等式,则算术实际上是无符号的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM