2016-11-16 100 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這是最大值爲簽名長)。

相關問題