为什么我不应该从Long.parseUnsignedLong获得一个值

时间:2016-11-16 15:55:36

标签: java long-integer primitive-types

当我这样做时

Long.parseUnsignedLong("FBD626CC4961A4FC", 16)

我回来了-300009666327239428

这似乎是错误的,因为根据这个答案https://stackoverflow.com/a/2550367/1754020,unsigned long的含义是范围总是正的。

要从此十六进制值中获取正确的数字

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

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

我再次得到-300009666327239428这个数字太大而且溢出了吗?

4 个答案:

答案 0 :(得分:5)

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

如果你有一个未签名的长

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

您可以使用函数

获取正确的字符串表示
String numberToPrint = Long.toUnsignedString(number);

如果您现在打印numberToPrint,则

18146734407382312188

更准确地说,您的号码仍然是常规的签名 long,这就是为什么如果直接打印就会显示溢出的原因。但是,有一些新的静态函数会将值视为无符号,例如此Long.toUnsignedString(long x)Long.compareUnsigned(long x, long y)

答案 1 :(得分:2)

转换为十进制的十六进制数#include <limits> #include <iostream> int main() { std::cout << "float\t" << std::numeric_limits<float>::lowest() << '\t' << std::numeric_limits<float>::max() << '\n'; std::cout << "double\t" << std::numeric_limits<double>::lowest() << '\t' << std::numeric_limits<double>::max() << '\n'; } 正好是"FBD626CC4961A4FC"。该数字确实大于最大可能18146734407382312188,定义为Long.MAX_VALUE且等于2 63 -1或long

9223372036854775807

因此,您回到负数是正常的。

您没有异常,因为Java 8中添加的新System.out.println(new BigInteger("FBD626CC4961A4FC", 16)); // 18146734407382312188 System.out.println(Long.MAX_VALUE); // 9223372036854775807 方法的目的正是为了能够处理无符号长整数(如compareUnsigned或{{3} })。由于Java divideUnsigned中的类型*Unsigned*,这些方法通过将负值理解为大于long的值来工作:它模拟无符号长整数。 is still unsigned说:

  

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

如果您打印的MAX_VALUElong的结果,并且它是否定的,则所有这意味着该值大于语言定义的最大长值,但是将unsigned longs作为参数的方法将正确解释这些值,就好像它们大于最大值一样。因此,如果您将该数字传递给parseUnsignedLong,而不是直接打印,您将获得正确的输出toUnsignedString。并非所有这些方法都是Java 8的新方法,例如like shown in this other answer也将给定的parseUnsignedLong解释为基数为16的unsigned long,而打印long将返回正确的十六进制字符串

仅当值无法表示为无符号长整数(即根本不是数字,或大于2 64 -1(而不是2 <)时,

toHexString才会抛出异常sup> 63 -1这是签名长的最大值。

答案 2 :(得分:1)

是的,当您尝试打印时,它会溢出,因为它会转换为Java long类型。要理解为什么让我们采用你的dec值的log2。

首先,原始值为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);打印正确的值

答案 3 :(得分:1)

内部无符号和带符号的数字以相同的方式表示,即在长的情况下为8字节。区别仅在于&#34;签署&#34;位解释,即如果您在C / C ++程序中执行相同操作并将值存储到uint64_t然后将其转换/映射到asigned int64_t,您应该得到相同的结果。

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