为什么我不应该从 Long.parseUnsignedLong 得到一个值
Why am I getting a value back from Long.parseUnsignedLong when I shouldn't be
当我做
Long.parseUnsignedLong("FBD626CC4961A4FC", 16)
我回来了-300009666327239428
这似乎是错误的,因为根据这个答案 unsigned long 的含义是范围总是正数。
为了从这个十六进制值中得到正确的数字,我做了
BigInteger value = new BigInteger("FBD626CC4961A4FC", 16);
当我打印值时,它会打印出正确的值。但如果我这样做 value.longValue()
我还是一样-300009666327239428
这是不是数字太大溢出了?
Java 8 确实(有点)支持 unsigned longs,但是,您不能直接打印它们。这样做会给您看到的结果。
如果你有一个 unsigned long
Long number = Long.parseUnsignedLong("FBD626CC4961A4FC", 16);
你可以用函数得到正确的字符串表示
String numberToPrint = Long.toUnsignedString(number);
如果你现在打印 numberToPrint
你会得到
18146734407382312188
更准确地说,您的号码仍将是常规 signed long
这就是为什么如果直接打印它会显示溢出。但是,有一些新的静态函数会将值视为无符号,例如 Long.toUnsignedString(long x)
或 Long.compareUnsigned(long x, long y)
。
是的,当您尝试打印它时它会溢出,因为它被转换为 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);
打印正确的值
内部无符号数和有符号数以相同的方式表示,即在 long 的情况下为 8 个字节。区别仅在于 "sign" 位的解释方式,即如果您在 C/C++ 程序中执行相同操作并将您的值存储到 uint64_t
中,然后将 cast/map 存储到赋值 int64_t
你应该得到相同的结果。
由于 8 字节或 64 位可以容纳的最大值是 2^64-1,因此这是此类数字的硬性约束。此外 Java 不直接支持无符号数,因此在 long
中存储无符号长整型的唯一方法是允许一个高于有符号 Long.MAX_VALUE
的值。事实上,Java 不知道您正在阅读的 string/hexcode 是表示有符号长整数还是无符号长整数,因此您可以通过转换回字符串或使用更大的数据类型,例如 BigInteger
.
十六进制数"FBD626CC4961A4FC"
,转换为十进制,正好是18146734407382312188
。该数字确实大于最大可能 long
,定义为 Long.MAX_VALUE
,等于 263-1,或 9223372036854775807
:
System.out.println(new BigInteger("FBD626CC4961A4FC", 16)); // 18146734407382312188
System.out.println(Long.MAX_VALUE); // 9223372036854775807
因此,返回负数是正常的。
你没有例外,因为这正是 Java 8 中添加的那些新 *Unsigned*
方法的目的,以提供处理无符号长整数的能力(如 compareUnsigned
or divideUnsigned
). Since the type long
in Java is still unsigned, those methods work by understanding negative values as values greater than MAX_VALUE
: it simulates an unsigned long. parseUnsignedLong
说:
An unsigned integer maps the values usually associated with negative numbers to positive numbers larger than MAX_VALUE
.
如果您打印 long
是 parseUnsignedLong
的结果,并且它是负数,这意味着该值大于语言定义的最大长值,但是采用无符号长整型作为参数的方法将正确解释这些值,就好像它们大于最大值一样。因此,不是直接打印它,如果您将该数字传递给 toUnsignedString
, you'll get the right output, . Not all of these methods are new to Java 8, for example toHexString
也将给定的 long
解释为基数为 16 的无符号长整型,并且打印 Long.toHexString(Long.parseUnsignedLong("FBD626CC4961A4FC", 16))
将返回您的权利十六进制字符串。
parseUnsignedLong
仅当该值不能表示为无符号长整数时才会抛出异常,即根本不是数字,或者大于 264-1 (而不是 263-1,它是有符号长整数的最大值)。
当我做
Long.parseUnsignedLong("FBD626CC4961A4FC", 16)
我回来了-300009666327239428
这似乎是错误的,因为根据这个答案 unsigned long 的含义是范围总是正数。
为了从这个十六进制值中得到正确的数字,我做了
BigInteger value = new BigInteger("FBD626CC4961A4FC", 16);
当我打印值时,它会打印出正确的值。但如果我这样做 value.longValue()
我还是一样-300009666327239428
这是不是数字太大溢出了?
Java 8 确实(有点)支持 unsigned longs,但是,您不能直接打印它们。这样做会给您看到的结果。
如果你有一个 unsigned long
Long number = Long.parseUnsignedLong("FBD626CC4961A4FC", 16);
你可以用函数得到正确的字符串表示
String numberToPrint = Long.toUnsignedString(number);
如果你现在打印 numberToPrint
你会得到
18146734407382312188
更准确地说,您的号码仍将是常规 signed long
这就是为什么如果直接打印它会显示溢出。但是,有一些新的静态函数会将值视为无符号,例如 Long.toUnsignedString(long x)
或 Long.compareUnsigned(long x, long y)
。
是的,当您尝试打印它时它会溢出,因为它被转换为 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);
内部无符号数和有符号数以相同的方式表示,即在 long 的情况下为 8 个字节。区别仅在于 "sign" 位的解释方式,即如果您在 C/C++ 程序中执行相同操作并将您的值存储到 uint64_t
中,然后将 cast/map 存储到赋值 int64_t
你应该得到相同的结果。
由于 8 字节或 64 位可以容纳的最大值是 2^64-1,因此这是此类数字的硬性约束。此外 Java 不直接支持无符号数,因此在 long
中存储无符号长整型的唯一方法是允许一个高于有符号 Long.MAX_VALUE
的值。事实上,Java 不知道您正在阅读的 string/hexcode 是表示有符号长整数还是无符号长整数,因此您可以通过转换回字符串或使用更大的数据类型,例如 BigInteger
.
十六进制数"FBD626CC4961A4FC"
,转换为十进制,正好是18146734407382312188
。该数字确实大于最大可能 long
,定义为 Long.MAX_VALUE
,等于 263-1,或 9223372036854775807
:
System.out.println(new BigInteger("FBD626CC4961A4FC", 16)); // 18146734407382312188
System.out.println(Long.MAX_VALUE); // 9223372036854775807
因此,返回负数是正常的。
你没有例外,因为这正是 Java 8 中添加的那些新 *Unsigned*
方法的目的,以提供处理无符号长整数的能力(如 compareUnsigned
or divideUnsigned
). Since the type long
in Java is still unsigned, those methods work by understanding negative values as values greater than MAX_VALUE
: it simulates an unsigned long. parseUnsignedLong
说:
An unsigned integer maps the values usually associated with negative numbers to positive numbers larger than
MAX_VALUE
.
如果您打印 long
是 parseUnsignedLong
的结果,并且它是负数,这意味着该值大于语言定义的最大长值,但是采用无符号长整型作为参数的方法将正确解释这些值,就好像它们大于最大值一样。因此,不是直接打印它,如果您将该数字传递给 toUnsignedString
, you'll get the right output, toHexString
也将给定的 long
解释为基数为 16 的无符号长整型,并且打印 Long.toHexString(Long.parseUnsignedLong("FBD626CC4961A4FC", 16))
将返回您的权利十六进制字符串。
parseUnsignedLong
仅当该值不能表示为无符号长整数时才会抛出异常,即根本不是数字,或者大于 264-1 (而不是 263-1,它是有符号长整数的最大值)。