2015-07-12 46 views
6

這是Java Api的錯誤嗎?用於32位有符號二進制字符串拋出的Java Integer.parseInt()NumberFormatException

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,我怎樣才能得到它的十進制數(-745203566)在Java中? DIY?編寫代碼來實現下面的等式?

enter image description here

回答

8

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

這些函數不能解釋binary的二進制補碼(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,然後更正該符號。回想一下,2的補碼= 1的補碼+1,而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的面膜吧),那麼降級longint。更快寫入,可能更快的代碼。

+1

請注意,一個簡短的方式來獲得一個有符號補數n的負等價物只是做〜n + 1 – fge

+0

我試圖繞過'Integer.valueOf'不解釋32位二進制補碼二進制字符串 - 所以我基本上做了'〜n'作爲一個字符串,並在解釋它之後做了'+ 1'。然而,在我寫了這個解決方案後,我意識到可以做'Long.parseLong(String,2)',以數字的形式進行二進制補碼運算,然後將其重新轉換爲int。 – Laogeodritt

+0

謝謝!總之,處理負數和基數是兩個時非常不直觀。但作爲一般API,它只能是這樣。 – zhuguowei

3

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

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

(自Java 8u25起)我認爲這是一個文檔錯誤,它應該是Integer.parseUnsignedInt(s, 2)。請注意0​​。這是因爲toBinaryString輸出將包含符號位。

編輯:請注意,即使這看起來像它會產生一個無符號值,它不是。這是因爲Java實際上沒有無符號值的概念,只有幾個靜態方法可以使用整數,就好像它們是 unsigned。

+0

看我的編輯:你已經有-745203566。 Java中沒有未簽名的整數。 – llogiq

+1

你有沒有至少試圖使用parseUnsignedInt而不是駁回我的答案?你根本不需要Integer.valueOf。 – llogiq

+0

像一個魅力工作 – kittyminky

相關問題