Java toByteArray()返回有目的的前导零?
我正在将bigint转换为二进制、radix16和radix64编码,并看到神秘的msb零填充。这是一个大整数问题,我可以通过去除零填充或者做其他事情来解决吗 我的测试代码:Java toByteArray()返回有目的的前导零?,java,biginteger,Java,Biginteger,我正在将bigint转换为二进制、radix16和radix64编码,并看到神秘的msb零填充。这是一个大整数问题,我可以通过去除零填充或者做其他事情来解决吗 我的测试代码: String s; System.out.printf( "%s length %d\n", s = "123456789A", (new BigInteger( s, 16 )).toByteArray().length ); System.out.printf( "%s length %d\n"
String s;
System.out.printf( "%s length %d\n", s = "123456789A", (new BigInteger( s, 16 )).toByteArray().length );
System.out.printf( "%s length %d\n", s = "F23456789A", (new BigInteger( s, 16 )).toByteArray().length );
产生输出:
123456789A length 5
F23456789A length 6
其中较长的数组前面有零填充。检查BigInteger.toByteArray()后,我看到:
现在,我可以找到私有int位长度代码>,但我找不到定义bitLength()的确切位置,以找出此类执行此操作的确切原因-可能连接到符号扩展?是的,这是:
字节数组将采用大端字节顺序:最高有效字节位于第0个元素中。数组将包含表示此BigInteger所需的最小字节数,至少包括一个符号位,即(ceil((this.bitLength()+1)/8))
作为:
返回此BigInteger
的最小二补表示形式中的位数,不包括符号位
换句话说,两个具有相同大小的值将始终具有相同的位长度,而不考虑符号。将biginger
视为无符号整数和符号位,而toByteArray()
返回两部分的所有数据,即“无符号整数所需的位数,符号所需的位数”。感谢Jon Skeet的回答。下面是我用来转换的一些代码,很可能是可以优化的
import java.math.BigInteger;
import java.util.Arrays;
public class UnsignedBigInteger {
public static byte[] toUnsignedByteArray(BigInteger value) {
byte[] signedValue = value.toByteArray();
if(signedValue[0] != 0x00) {
throw new IllegalArgumentException("value must be a psoitive BigInteger");
}
return Arrays.copyOfRange(signedValue, 1, signedValue.length);
}
public static BigInteger fromUnsignedByteArray(byte[] value) {
byte[] signedValue = new byte[value.length + 1];
System.arraycopy(value, 0, signedValue, 1, value.length);
return new BigInteger(signedValue);
}
}
当我搜索(10)这些数字时,我得到的是78187493530和1040260167834的正值,所以对我来说这更像是一个bug。但不管怎样,我可以忍受一个bug——我只是想知道去掉前导零是否安全。@Orthoteroid:你把它们看作十进制值——试着打印二进制值吧。。。毕竟,您是在尝试计数位,而不是十进制数字。至于去掉前导零是否“安全”,这取决于您以后将如何处理它。为了澄清,我确实不能接受toByteArray返回的非填充前导零,因为我的目的是跨平台基数转换。不过你的评论很有帮助-我可以使用toString(基数),我将得到一个未添加的位字符串。“我必须带着它飞行。”@Orthoteroid:那么你要如何区分负值和非负值呢?如果第一位(或最后一位)始终是符号位(无论是0还是1),则很容易实现。如果您只需要处理非负值,那么您就可以了,但除此之外,您真的需要考虑一下。@Orthoteroid:只需将字节视为8位数据,不管您想如何使用它们。现在认为BigInteger的表示是一个量级和一个符号(如文档所示)。因此,您有9位数据,不能放入1个字节。再次-考虑一下,如果调用toByteArray,您希望表示-1的BigInteger做什么。从我与Jon的讨论中,我认为您可能需要将arg左移到带有零字节的fromUnsignedByte-否则,如果arg设置了高位,您的返回值将为负值。没有?啊!我知道你现在做了什么。只是添加一个注释,说明代码不正确。Java BigInteger只有在其大小中设置了最高位(不包括符号位)的正值时才有额外的零字节前缀。原始帖子中的输入清楚地表明了这一点F23456789A
在设置的第一个字节中有最高的位,因此它需要额外的字节(包含符号位)<代码>123456789A
没有。同样地,723456789A
没有。但是823456789A
。这很容易检查。
import java.math.BigInteger;
import java.util.Arrays;
public class UnsignedBigInteger {
public static byte[] toUnsignedByteArray(BigInteger value) {
byte[] signedValue = value.toByteArray();
if(signedValue[0] != 0x00) {
throw new IllegalArgumentException("value must be a psoitive BigInteger");
}
return Arrays.copyOfRange(signedValue, 1, signedValue.length);
}
public static BigInteger fromUnsignedByteArray(byte[] value) {
byte[] signedValue = new byte[value.length + 1];
System.arraycopy(value, 0, signedValue, 1, value.length);
return new BigInteger(signedValue);
}
}