2016-11-16 98 views
3

当我做为什么我会得到一个值回从Long.parseUnsignedLong时,我不应该

Long.parseUnsignedLong("FBD626CC4961A4FC", 16) 

我回来-300009666327239428

这似乎错了,因为无符号长按的意义这个回答https://stackoverflow.com/a/2550367/1754020是范围总是正面的。

要想从这个十六进制值正确的号码,我做

BigInteger value = new BigInteger("FBD626CC4961A4FC", 16); 

当我打印值它打印正确的值。但如果我做value.longValue()

再次我得到相同的-300009666327239428是这个数字太大,溢出?

+3

打印'Long.MAX_VALUE'并进行比较。是的,这太大了,不适合“长”。 – Tunaki

+0

所以它不会抛出异常? –

+1

[文档](https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html#parseUnsignedLong-java.lang.String-int-)声称它应该抛出一个' NumberFormatException'如果“字符串表示的值大于最大的无符号长整数2^64-1”。 对不起,我没有回答。 – tsm

回答

5

Java 8确实(有点)支持unsigned longs,但是,您不能直接打印它们。这样做会给你看到的结果。

如果你有一个unsigned long

Long number = Long.parseUnsignedLong("FBD626CC4961A4FC", 16); 

你可以用功能

String numberToPrint = Long.toUnsignedString(number); 

正确的字符串表示如果现在打印numberToPrint

18146734407382312188 

要更确切地说,你的号码仍然是一个普通的signedlong这就是为什么直接打印时显示溢出的原因。但是,有一些新的静态函数会将该值视为未签名,如Long.toUnsignedString(long x)Long.compareUnsigned(long x, long y)

+0

关于'Long.toUnsignedString(number)'是非常好的一点' – Andremoniy

1

是的,它会在您尝试打印时溢出,因为它会转换为Java long类型。要理解为什么让我们取log 12的dec值。

首先,原始值是18146734407382312188。它的log2是〜63.9763437545。

二,查看documentation:在java long类型中,表示值为-2^63,最大值为2^63-1。

所以,你的价值是明显大于2^63-1,因此它溢出:

-2^63 + (18146734407382312188 - 2^63 + 1) = -300009666327239428 

但作为@Keiwan出色提到的,你仍然可以使用Long.toUnsignedString(number);

1

内部无符号打印正确的值并且有符号的数字以相同的方式表示,即在长的情况下为8个字节。区别仅在于“符号”位的解释方式,即如果您在C/C++程序中执行相同操作并将您的值存储到uint64_t中,然后将其映射到映射的int64_t,则应得到相同的结果。

由于8个字节或64位可以容纳的最大值是2^64-1,这就是这些数字的硬约束。此外,Java不直接支持无符号数字,因此在long中存储无符号长整数的唯一方法是允许一个高于签名Long.MAX_VALUE的值。事实上,Java并不知道您读取的字符串/十六进制代码是表示有符号还是无符号长整型,因此您可以通过将其转换回字符串或使用更大的数据类型(如BigInteger)来提供该解释。

2

转换为十进制的十六进制数"FBD626CC4961A4FC"恰好为18146734407382312188。这个数字确实比最大可能long较大,定义为Long.MAX_VALUE和等于2 -1,或9223372036854775807

System.out.println(new BigInteger("FBD626CC4961A4FC", 16)); // 18146734407382312188 
System.out.println(Long.MAX_VALUE);       // 9223372036854775807 

这样,你得到一个负数是正常的。

你没有一个例外,因为它是完全的在Java中添加8这些新​​3210方法的目的,给予办理无符号长整型(如compareUnsigneddivideUnsigned)的能力。由于Java is still unsigned中的类型为long,这些方法通过将负值理解为大于MAX_VALUE的值来工作:它模拟无符号长整型。 parseUnsignedLong说:

无符号整数将通常与负数相关的值映射到大于MAX_VALUE的正数。

如果打印long那是的parseUnsignedLong的结果,它是消极的,它的意思是,该值大于最大长值由语言定义的,但方法以无符号多头为参数将正确解释这些值,就好像它们大于最大值一样。因此,如果您将该号码传递给toUnsignedString,您将得到正确的输出like shown in this other answer,而不是直接打印。并非所有这些方法对于Java 8都是新手,例如toHexString也将给定的long解释为基数为16的无符号长整数,并且打印Long.toHexString(Long.parseUnsignedLong("FBD626CC4961A4FC", 16))将使您返回正确的十六进制字符串。

parseUnsignedLong将抛出仅当该值不能被表示为无符号长异常,即不是一个数字在所有,或大于2 -1(和2不 -1这是最大值为签名长)。

相关问题