Java中二进制和十进制整数之间相互转换的思考
2011-08-19 13:48
507 查看
我的一个项目需要经常用到二进制和十进制整数之间的相互转换。这应该是个非常容易实现的问题,所用到的算法也极其简单。Java更是提供了Integer.toBinaryString(int number)方法直接获取某个十进制的二进制字符串表示。在二进制转换十进制方面可以使用Java的Integer.valueOf(String s, int radix); 这里的radix就是进制。Integer.valueOf(String s, 2);这条语句就能轻而易举的把字符串表示的二进制转成十进制整数。
可见,在Java中完成二进制和十进制整数之间相互转换简直太easy了。
由于项目中需要的二进制char数组表示而非字符串表示,于是我就直接把这两个方法简单进行封装得到以下代码:
import java.util.Arrays; /** * 二进制和数字之间相互转换类 * <pre> * email: yangzhengzheng1985@163.com * time: 2011/8/18 7:30 * </pre> * @author 杨争争 * */ public class BinaryCharArrayNumberTransfer1 { /** * 转换整型为二进制char数组 * @param number 给定整数 * @param dimensionOfCharArray 二进制数组的位数 * @return number的二进制组成的char数组 */ public static char[] transferNumber2CharArray(int number, int dimensionOfCharArray) { char[] src = Integer.toBinaryString(number).toCharArray(); char[] dest = new char[dimensionOfCharArray]; System.arraycopy(src, 0, dest, dimensionOfCharArray - src.length, src.length); for (int i = 0; i < 32 - src.length; i++) dest[i] = '0'; return dest; } /** * 二进制char数组转换为整数 * @param ch 二进制数组 * @return 二进制表示的整数 */ public static int transferCharArray2Number(char[] ch) { if (ch.length != 32) throw new RuntimeException("数组大小必须为32位"); String s = new String(ch); return Integer.valueOf(s, 2); } // for test public static void main(String[] args) { for (int i = -10; i <= 10; i++) { char[] ch = BinaryCharArrayNumberTransfer1.transferNumber2CharArray( i, 32); System.out.println("十进制转换二进制: " + i + "-->" + Arrays.toString(ch)); int num = BinaryCharArrayNumberTransfer1 .transferCharArray2Number(ch); System.out.println("二进制转换十进制: " + num); System.out.println("-----------"); } } }
但是,在测试这两个方法的时候却得到了意外的结果。
方法transferNumber2CharArray没有任何问题。问题主要出在transferCharArray2Number上,当传入的参数是一个负数的二进制char数组时,运行会报java.lang.NumberFormatException。用-10进行测试,得到以下结果:
十进制转换二进制: -10-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0]
Exception in thread "main" java.lang.NumberFormatException: For input string: "11111111111111111111111111110110"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:461)
at java.lang.Integer.valueOf(Integer.java:528)
at BinaryCharArrayNumberTransfer.transferCharArray2Number(BinaryCharArrayNumberTransfer.java:57)
at BinaryCharArrayNumberTransfer.main(BinaryCharArrayNumberTransfer.java:67)
这说明十进制被成功转换成了二进制,但是相应的二进制并没有成功转成十进制。因为在执行转换过程中报了 java.lang.NumberFormatException,转换过程被迫终止。去掉测试中的非正整数测试数据,异常消失,转换成功。这是为什么呢?
查看jdk源代码,发现valueOf方法调用了parseInt方法。
public static Integer valueOf(String s, int radix) throws NumberFormatException { return Integer.valueOf(parseInt(s,radix)); }
public static int parseInt(String s, int radix) throws NumberFormatException { if (s == null) { throw new NumberFormatException("null"); } if (radix < Character.MIN_RADIX) { throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX"); } if (radix > Character.MAX_RADIX) { throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX"); } int result = 0; boolean negative = false; int i = 0, max = s.length(); int limit; int multmin; int digit; if (max > 0) { if (s.charAt(0) == '-') { negative = true; limit = Integer.MIN_VALUE; i++; } else { limit = -Integer.MAX_VALUE; } multmin = limit / radix; if (i < max) { digit = Character.digit(s.charAt(i++),radix); if (digit < 0) { throw NumberFormatException.forInputString(s); } else { result = -digit; } } while (i < max) { // Accumulating negatively avoids surprises near MAX_VALUE digit = Character.digit(s.charAt(i++),radix); if (digit < 0) { throw NumberFormatException.forInputString(s); } if (result < multmin) { throw NumberFormatException.forInputString(s); } result *= radix; if (result < limit + digit) { throw NumberFormatException.forInputString(s); } result -= digit; } } else { throw NumberFormatException.forInputString(s); } if (negative) { if (i > 1) { return result; } else { /* Only got "-" */ throw NumberFormatException.forInputString(s); } } else { return -result; } }
parseInt方法中有一句 if
(s.charAt(0) == '-'),这是什么意思?传入的二进制字符串不应该只有0,1吗?这个"-"有什么特别之处吗?难道这个"-"是用来表示二进制的正负的?如果那样的话,Integer.toBinaryString(int)返回的就应该是无符号位的二进制字符串。马上查看Integer.toBinaryString(int)的源码。
public static String toBinaryString(int i) { return toUnsignedString(i, 1); }
返回的的确是无符号位的二进制字符串。至此,原因找到了。看来之前并没有注意到JDK API的这些细节啊,让我这边排查了好一会,惭愧!
当传入的参数是负整数的二进制的时候Integer.valueOf(String, 2)是不能用了。该怎么办呢?
最直接的方法就是自己实现。负数的二进制是补码表示,非正整数的原码表示,所以可以通过原码=补码取反+1重新构造二进制字符串。最终结果就是构造后的二进制字符串转换成整数,前面加上一个负号。取反操作很容易实现,+1涉及到进位操作,有点小麻烦。能不能利用JDK
API已有的方法,这样既能避免麻烦,还可以提高性能,毕竟JDK经过多个版本更新和N多实际项目考验,性能肯定比自己写的方法要好些。
经过思考,我想到以下办法。假设{X}表示为X的十进制表示
1. 原码=补码取反+1, 则原码-1=补码取反
2. {原码-1} = {补码取反} ==> -({原码} - 1) = - {补码取反} ==> -{原码} + 1 = - {补码取反} ==> -{原码}
= - {补码取反} - 1
3. 由于 {一个负数} = - {原码} 所以 {一个负数} = = - {补码取反} - 1。
例如-3的二进制是1111 1101(假设共8位), 求反得到0000 0010(2), 加上负号得到-2, 再减去1,得-3.
所以上述结论是成立的。{补码取反}刚好可以通过Integer.valueOf(String, 2)计算。剩下要做的工作就只是对字符串取反了。
根据以上思路,我修改了Java代码,并进行简单测试。
import java.util.Arrays; /** * 二进制和数字之间相互转换类 * <pre> * email: yangzhengzheng1985@163.com * time: 2011/8/18 8:30 * </pre> * @author 杨争争 * */ public class BinaryCharArrayNumberTransfer { /** * 转换整型为二进制char数组 * @param number 给定整数 * @param dimensionOfCharArray 二进制数组的位数 * @return number的二进制组成的char数组 */ publi 112b5 c static char[] transferNumber2CharArray(int number, int dimensionOfCharArray) { char[] src = Integer.toBinaryString(number).toCharArray(); char[] dest = new char[dimensionOfCharArray]; System.arraycopy(src, 0, dest, dimensionOfCharArray - src.length, src.length); for (int i = 0; i < 32 - src.length; i++) dest[i] = '0'; return dest; } /** * 二进制char数组转换为整数 * @param ch 二进制数组 * @return 二进制表示的整数 */ public static int transferCharArray2Number(char[] ch) { if (ch.length != 32) throw new RuntimeException("数组大小必须为32位"); String s = null; // 正数 if (ch[0] == '0') { s = new String(ch); return Integer.valueOf(s, 2); } else { for (int i = 0; i < 32; i++) { if (ch[i] == '0') ch[i] = '1'; else ch[i] = '0'; } s = "-" + new String(ch); // 结果修正 return Integer.valueOf(s, 2) - 1; } } // for test public static void main(String[] args) { for (int i = -10; i <= 10; i++) { char[] ch = BinaryCharArrayNumberTransfer.transferNumber2CharArray( i, 32); System.out.println("十进制转换二进制: " + i + "-->" + Arrays.toString(ch)); int num = BinaryCharArrayNumberTransfer .transferCharArray2Number(ch); System.out.println("二进制转换十进制: " + num); System.out.println("-----------"); } } }
运行结果如下:
十进制转换二进制: -10-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0]
二进制转换十进制: -10
-----------
十进制转换二进制: -9-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1, 1, 1]
二进制转换十进制: -9
-----------
十进制转换二进制: -8-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
二进制转换十进制: -8
-----------
十进制转换二进制: -7-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1]
二进制转换十进制: -7
-----------
十进制转换二进制: -6-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 1, 0]
二进制转换十进制: -6
-----------
十进制转换二进制: -5-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 1, 1]
二进制转换十进制: -5
-----------
十进制转换二进制: -4-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0]
二进制转换十进制: -4
-----------
十进制转换二进制: -3-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 1]
二进制转换十进制: -3
-----------
十进制转换二进制: -2-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
二进制转换十进制: -2
-----------
十进制转换二进制: -1-->[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
二进制转换十进制: -1
-----------
十进制转换二进制: 0-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
二进制转换十进制: 0
-----------
十进制转换二进制: 1-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
二进制转换十进制: 1
-----------
十进制转换二进制: 2-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
二进制转换十进制: 2
-----------
十进制转换二进制: 3-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1]
二进制转换十进制: 3
-----------
十进制转换二进制: 4-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
二进制转换十进制: 4
-----------
十进制转换二进制: 5-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 1]
二进制转换十进制: 5
-----------
十进制转换二进制: 6-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0]
二进制转换十进制: 6
-----------
十进制转换二进制: 7-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1]
二进制转换十进制: 7
-----------
十进制转换二进制: 8-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
二进制转换十进制: 8
-----------
十进制转换二进制: 9-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 1]
二进制转换十进制: 9
-----------
十进制转换二进制: 10-->[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 1, 0]
二进制转换十进制: 10
-----------
从程序运行结果看,问题得到解决。
相关文章推荐
- Java 二进制,八进制,十进制,十六进制之间的相互转换
- [JAVA]二进制,八进制,十六进制,十进制间进行相互转换
- 二进制 十进制和byte之间相互转换
- [JAVA]二进制,八进制,十六进制,十进制间进行相互转换
- java中进行二进制,八进制,十六进制,十进制间进行相互转换
- java中进行二进制,八进制,十六进制,十进制间进行相互转换
- java中各进制之间的转换(十进制转十六进制、十进制转二进制、二进制转十进制、二进制转十六进制)
- 二进制,八进制,十进制与十六进制之间的相互转换
- IP地址在“点分十进制”和“二进制整数”之间转换
- java 二进制,八进制,十六进制,十进制间进行相互转换
- 二进制、八进制、十进制、十六进制之间的相互转换
- java写十进制二进制相互转换
- [JAVA]二进制,八进制,十六进制,十进制间进行相互转换
- java 二进制,八进制,十进制,十六进制间相互转换的方法
- java 十进制整数转换为二进制!
- java: 查表法将十进制整数转换成二进制、八进制、十六进制
- 二进制、八进制、十进制、十六进制之间的相互转换
- Java使用bit array实现二进制,十进制,十六进制值之间的转换
- java中进行二进制,八进制,十六进制,十进制间进行相互转换
- 实现二进制与十进制之间的相互转换