簡體   English   中英

用於 32 位有符號二進制字符串的 Java Integer.parseInt() 拋出 NumberFormatException

[英]Java Integer.parseInt() for 32-bit signed binary string throws NumberFormatException

這是 Java Api 的錯誤嗎?

    int i = 0xD3951892;
    System.out.println(i); // -745203566
    String binString = Integer.toBinaryString(i);
    int radix = 2;
    int j = Integer.valueOf(binString, radix );
    Assertions.assertThat(j).isEqualTo(i);

我希望它毫無疑問地是真的。 但它拋出以下異常:

java.lang.NumberFormatException: For input string: "11010011100101010001100010010010"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:495)
at java.lang.Integer.valueOf(Integer.java:556)
at com.zhugw.temp.IntegerTest.test_valueof_binary_string(IntegerTest.java:14)

因此,如果我有一個二進制字符串,例如 11010011100101010001100010010010,我如何在 Java 中獲得它的十進制數(-745203566)? DIY? 編寫代碼來實現下面的等式?

在此處輸入圖片說明

Integer.valueOf(String, int radix)Integer.parseInt(String, int radix)只會解析值 -2 147 483 648 到 2 147 483 647 的數字,即 32 位有符號整數的值。

這些函數無法解釋二進制 ( radix = 2 ) 的二進制補碼,因為傳遞的字符串可以是任意長度,因此前導 1 可能是數字或符號位的一部分。 我猜 Java 的開發人員認為最合乎邏輯的方法是永遠不要接受二進制補碼,而不是假設第 32 位是符​​號位。

他們將您的輸入二進制字符串讀取為無符號 3 549 763 730(大於最大 int 值)。 要讀取負值,您需要給出一個前面帶有-符號的正二進制數。 例如-5

Integer.parseInt("1011", 2); // 11
    // Even if you extended the 1s to try and make two's complement of 5,
    // it would always read it as a positive binary value
Integer.parseInt("-101", 2); // -5, this is right

解決方案:

我建議,首先,如果您可以將其存儲為帶有您自己的額外符號信息的正數(例如-符號),請執行此操作。 例如:

String binString;
if(i < 0)
    binString = "-" + Integer.toBinaryString(-i);
else // positive i
    binString = Integer.toBinaryString(i);

如果需要使用帶符號的二進制字符串,為了取二進制補碼形式的負數(作為字符串)並解析為int,建議您手動取二進制補碼,將其轉換為int,然后更正標志。 回想一下,二的補碼 = 一的補碼 + 1,而一的補碼只是反轉每一位。

作為示例實現:

String binString = "11010011100101010001100010010010";
StringBuilder onesComplementBuilder = new StringBuilder();
for(char bit : binString.toCharArray()) {
    // if bit is '0', append a 1. if bit is '1', append a 0.
    onesComplementBuilder.append((bit == '0') ? 1 : 0);
}
String onesComplement = onesComplementBuilder.toString();
System.out.println(onesComplement); // should be the NOT of binString
int converted = Integer.valueOf(onesComplement, 2);
// two's complement = one's complement + 1. This is the positive value
// of our original binary string, so make it negative again.
int value = -(converted + 1);

您還可以為 32 位二進制補碼編寫自己的Integer.parseInt版本。 當然,這假設您沒有使用 Java 8 並且不能只使用Integer.parseUnsignedInt ,@llogiq 在我輸入時指出了這一點。

編輯:您也可以先使用Long.parseLong(String, 2) ,然后計算二進制補碼(並用 0xFFFFFFFF 將其屏蔽),然后將long降級為int 寫得更快,可能更快的代碼。

Integer.toBinaryString(..)的 API 文檔明確指出:

可以通過調用Integer.parseUnsignedInt(s, 8)從返回的字符串 s 中恢復參數的值。

(從 Java 8u25 開始)我認為這是一個文檔錯誤,它應該讀取Integer.parseUnsignedInt(s, 2) 注意Unsigned 這是因為toBinaryString輸出將包含符號位。

編輯:請注意,即使這看起來會產生無符號值,但事實並非如此。 這是因為Java並沒有真正具有無符號值的概念,只有幾個靜態方法與整數工作,好像他們無符號。

我正在努力解決類似的問題,Ilogic的上述回答對我來說非常有效。 謝謝。 :)。 如果我能投票贊成而不是在這里發表,我會的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM