二进制转十进制
问题背景
本问题要求实现一个程序,该程序能够接收一个以字符串形式表示的二进制数,并将其转换为对应的十进制整数。
核心规则:二进制补码
需要特别注意的是,输入的二进制字符串代表的是一个整数的**二进制补码(Two's Complement)**形式。这是计算机系统中表示有符号整数(正数、负数和零)的标准方式。
-
对于32位整数:
- 如果最高位(从左数第1位,或从右数第32位)是
0,则该数表示一个正数或零。 - 如果最高位是
1,则该数表示一个负数。
- 如果最高位(从左数第1位,或从右数第32位)是
任务要求
给定一个二进制字符串,请将其从二进制补码形式转换成标准的十进制整数。
输入格式
-
一个字符串,代表一个二进制数。
- 字符串中仅包含字符
'0'和'1'。 - 用例保证:输入字符串转换后的结果总是在 32位有符号整数 的范围内(即从
-2,147,483,648到2,147,483,647)。
- 字符串中仅包含字符
输出格式
- 一个十进制整数,表示输入二进制字符串所对应的数值。
资源限制
- 时间限制: C/C++
1000ms, 其他语言2000ms - 内存限制: C/C++
64MB, 其他语言128MB
样例说明
样例 1
-
输入:
"00011" -
输出:
3 -
解释:
-
二进制
00011的最高有效位是0,表示这是一个正数。 -
其值按标准二进制转十进制计算:
(0⋅24)+(0⋅23)+(0⋅22)+(1⋅21)+(1⋅20)=0+0+0+2+1=3
-
因此,结果为
3。
-
样例 2
-
输入:
"11111111111111111111111111111111" -
输出:
-1 -
解释:
- 这是一个长度为 32 的二进制字符串,其最高位(最左边的位)是
1。 - 根据二进制补码规则,这表示一个负数。
- 在32位有符号整数的补码表示法中,全为
1的二进制数1111...1111(共32个1) 正好代表十进制整数 -1。 - 因此,结果为
-1。
- 这是一个长度为 32 的二进制字符串,其最高位(最左边的位)是
这个问题的关键点在于理解题目中提到的“二进制字符串表示的是整数的补码形式”。这意味着一个32位的二进制串,如果其最高位(第32位,从右数)是1,那么它代表一个负数。
解决这个问题的最简洁、最健壮的方法是利用Java的内置解析函数,但需要一个小技巧来正确处理32位负数的情况:
- 使用
Long.parseLong: 我们不直接使用Integer.parseInt,因为它在解析一个32位且最高位为1的二进制串时,会认为这是一个超出int正数范围的大数,从而抛出异常。相反,我们使用Long.parseLong,它可以无误地将这个32位二进制串解析成一个正的long值。 - 类型转换: 将上一步得到的
long值强制转换为int。在Java中,这种从长类型到短类型的转换(窄化转换)会截取低位。对于一个32位的二进制补码表示,这个截取操作恰好能得到其对应的有符号int值。例如,二进制的1111...1111(32个1)被解析为long类型的2^32 - 1,当它被强制转换为int时,其二进制表示不变,而这正是int类型中-1的补码表示。
这种方法巧妙地利用了Java的类型转换规则来完成补码的解释。
public class BinaryConverter {
/**
* 主方法,将一个表示二进制补码的字符串转换为其对应的十进制整数.
*
* @param binaryStr 一个仅包含 '0' 和 '1' 的二进制字符串
* @return 转换后的十进制整数
*/
public int binaryToDecimal(String binaryStr) {
// --- 核心逻辑:利用 Long.parseLong 和类型转换为 int 来处理32位补码 ---
// 步骤 1: 使用 Long.parseLong 将二进制字符串按基数2进行解析。
// 我们选择解析为 long 类型而不是 int 类型,是为了避免处理32位负数时出现 NumberFormatException。
// 例如,对于二进制 "11111111111111111111111111111111":
// - 如果使用 Integer.parseInt(s, 2),它会尝试解析一个非常大的正数,这会超出 int 的最大值,从而抛出异常。
// - 而 Long.parseLong(s, 2) 可以无误地将其解析为一个正的 long 值 (2^32 - 1)。
long longValue = Long.parseLong(binaryStr, 2);
// 步骤 2: 将解析出的 long 值强制转换为 int。
// 这是本算法最巧妙的一步。在Java中,从 long 到 int 的窄化原始类型转换会丢弃高32位,只保留低32位。
// 这个行为与计算机处理二进制补码的方式完全一致。
// - 对于正数(如 "00011" -> 3L),转换后仍然是 3。
// - 对于负数(如 "1111...1111" -> 4294967295L),其二进制的低32位与 int 类型中 -1 的补码表示完全相同,
// 因此强制转换后会得到正确的结果 -1。
return (int) longValue;
}
}