Java 如何转换一个";“未签名”;长到大整数
如果我有一个JavaJava 如何转换一个";“未签名”;长到大整数,java,long-integer,biginteger,Java,Long Integer,Biginteger,如果我有一个Javalong值,比如说x,它应该被解释为无符号值(即0x8000_0000_0000_0000和更高的值应该被解释为正值),那么我如何将它转换为biginger 显然,biginger.valueOf(x)将导致负值,转换为十六进制或字节似乎是浪费。实际上,转换非常简单。可以使用类似于将无符号整数转换为长整数的掩码: 让我们首先将掩码创建为常量(这只会将最低有效32位设置为1): 因此,对于biginger我们可以创建如下掩码(64个最低有效位设置为1): 太好了,那么剩下的
long
值,比如说x
,它应该被解释为无符号值(即0x8000_0000_0000_0000
和更高的值应该被解释为正值),那么我如何将它转换为biginger
显然,
biginger.valueOf(x)
将导致负值,转换为十六进制或字节似乎是浪费。实际上,转换非常简单。可以使用类似于将无符号整数转换为长整数的掩码:
让我们首先将掩码创建为常量(这只会将最低有效32位设置为1):
因此,对于
biginger
我们可以创建如下掩码(64个最低有效位设置为1):
太好了,那么剩下的就简单了:
long unsignedLong = 0x8000_0000_0000_0000L; // sample input value
BigInteger bi = BigInteger.valueOf(unsignedLong).and(UNSIGNED_LONG_MASK);
这不是火箭科学,但有时你只是想找到一个简单快捷的答案。这个转换实际上是在OpenJDK的
java.lang.Long
中实现的。但它是私人的,所以将其粘贴到此处:
/**
* Return a BigInteger equal to the unsigned value of the
* argument.
*/
private static BigInteger toUnsignedBigInteger(long i) {
if (i >= 0L)
return BigInteger.valueOf(i);
else {
int upper = (int) (i >>> 32);
int lower = (int) i;
// return (upper << 32) + lower
return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
}
}
/**
*返回一个BigInteger,该值等于
*争论。
*/
私有静态BigInteger toUnsignedBigInteger(长i){
如果(i>=0L)
返回BigInteger.valueOf(i);
否则{
整数上限=(整数)(i>>>32);
整数下限=(整数)i;
//return(在我的机器上,使用长到字节数组的转换速度快了6倍这是一个真正的魔法(intrinsics)继续。我现在会检查哪一个更快。你测试过生成掩码还是不生成掩码吗?我刚刚用你的代码生成了BigInteger。UNSIGNED_LONG_mask
当然是静态字段,最后两行代码会被测量。还有什么可以改进的?(unsignedLong
取自ThreadLocalRandom
,但我认为这无关紧要)在测量中使用随机是相当棘手的-如果它阻止了测量,那么你的测量就关闭了,并且随机生成通常使用一个繁重的加密算法。然后在JIT编译开始之前有JVM时间。最后,你有字节数组的垃圾收集,这可能只有在你执行测试之后才开始…这是主题并不像看上去那么简单。嗯,链接是错误的:
// use "import static java.math.BigInteger.ONE;" to shorten this line
private static final BigInteger UNSIGNED_LONG_MASK = BigInteger.ONE.shiftLeft(Long.SIZE).subtract(BigInteger.ONE);
long unsignedLong = 0x8000_0000_0000_0000L; // sample input value
BigInteger bi = BigInteger.valueOf(unsignedLong).and(UNSIGNED_LONG_MASK);
/**
* Return a BigInteger equal to the unsigned value of the
* argument.
*/
private static BigInteger toUnsignedBigInteger(long i) {
if (i >= 0L)
return BigInteger.valueOf(i);
else {
int upper = (int) (i >>> 32);
int lower = (int) i;
// return (upper << 32) + lower
return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
}
}