【题目链接】
【题目考点】
1. 机器码
- 非负数的原码、反码、补码相同。
- 负数
- 原码:符号位是1
- 反码:各位取反,符号位不变
- 补码:反码加1,符号位不变
2. 数制
3. 高精度
4. 位运算
【解题思路】
解法1:使用数字数组
使用数字数组a,从低位到高位保存机器码的各个数位,模拟求补码的过程。
如果数字n是负数,那么将a的最高位(第32位)设为1,将n变为n的相反数,变成正数。
而后对数字n做二进制下的数字拆分,将n转为二进制数字,填充到数字a。当前数组a就是数字n的原码。
- 如果n是非负数,那么原码就是补码,直接输出数组a。
- 如果n是负数,而后对第1到第31位取反,得到反码。接着对这个反码加1,方法为:从低位开始,只要遇到1,就将其变为0,再看下一位。直到遇到一个0,将这个0变为1,结束。
已知32位的有符号整型可以表示的数字范围为:
−
2
32
∼
2
32
−
1
-2^{32}\sim2^{32}-1
−232∼232−1,
−
2
32
-2^{32}
−232这个数字的补码很特别,是1后面接31个0。最高位第32位既是符号位表示负数,又表示数值。
−
2
32
-2^{32}
−232在十六进制下为
0
x
80000000
0x80000000
0x80000000,十进制下为
−
2147483648
-2147483648
−2147483648。如果输入的是这个值,根据上述逻辑,对这个值取反,会得到2147483648,也就是
2
32
2^{32}
232,而这个值是无法用int类型表示的,用int类型保存这个值会产生错误。
因此,为了能够让
−
2
32
-2^{32}
−232成功取反,变量n及相关变量要声明成long long。
解法2:使用位运算
数字在计算机内存中都是以补码形式保存的,也就是说机器码都是补码。而位运算正是处理变量的机器码的运算。
输入数字n,循环32次,每次循环做:
- 取数字n机器码的最低位(
n%2
是做不到的,因为n为负数时取模会得到负数)。这里要使用按位与(&),用n按位与1:如果n的最低位是1,结果就是1。如果n的最低位是0,结果就是0。所以n&1
就是n这个数字的机器码的最低位。将这个数字变为字符,接在表示补码的字符串上。 - 而后让n去掉刚才已经取出的一位,即右移一位,写法为
n = n>>1
或n >>= 1
最后输出拼接后的表示补码的字符串。
注意:按位与&的运算优先级比算术运算符低,使用时要加括号。
【题解代码】
解法1:使用数字数组 模拟
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long n;
int a[33] = {}, ai = 0;
cin >> n;
if(n < 0)
{
a[32] = 1;
n = -n;
}
for(long long i = n; i > 0; i /= 2)
a[++ai] = i%2;
if(a[32] == 1)
{
for(int i = 1; i < 32; ++i)
a[i] = !a[i];
for(int i = 1; i < 32; ++i)
{
if(a[i] == 1)
a[i] = 0;
else
{
a[i] = 1;
break;
}
}
}
for(int i = 32; i >= 1; i--)
cout << a[i];
return 0;
}
解法2:使用位运算
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s;
int n;
cin >> n;
for(int i = 1; i <= 32; ++i)
{
s = char((n&1)+'0')+s;
n >>= 1;
}
cout << s;
return 0;
}