有这么一道题目:
编写函数,实现输入一个数,输出该数的原码、反码和补码
一开始我并没有用位运算的思路,于是写下了下面长长的一段代码:
(假设我输入-1754)
#include <stdio.h>
#include <math.h>
int positive(int num) //用于计算正数
{
int i,a[1000],b=1,c;
for (i=0; i<1000; i++) {
a[i]=num%2;
num=num/2;
if (num<1)
{
b=i;
break;
}
}
a[b+1]=0;
printf("ture code is ");
for (i=b+1; i>=0; i--)
{
printf("%d",a[i]);
}
printf("\nones-complement code is ");
for (i=b+1; i>=0; i--) {
c=a[i];
c=~c&1; //必须要有,不然会11111111的c
printf("%d",c);
}
printf("\ncomplemental code is ");
for (i=b+1; i>=0; i--)
{
printf("%d",a[i]);
}
printf("\n");
return 0;
}
int negetive(int num) //计算负数
{
int i,a[1000],d[1000],b=1,c,e = 0,numb;
numb=num;
num=-num;
for (i=0; i<1000; i++) {
a[i]=num%2;
num=num/2;
if (num<1)
{
b=i;
break;
}
}
num=-numb;
num=~num; //此处num输出会出现-1755,原因是现在机器普遍用补码表示负数
num=num+1;
printf("%d\n",num);
for (i=0; i<1000; i++) {//注意此处for循环是错误的
d[i]=num%2;
num=num/2;
if (num>-1)
{
e=i;
break;
}
}
a[b+1]=1;
d[e+1]=1;
printf("ture code is ");
for (i=b+1; i>=0; i--)
{
printf("%d",a[i]);
}
a[b+1]=0;
printf("\nones-complement code is ");
for (i=b+1; i>=0; i--) {
c=a[i];
c=~c&1; //必须要有不然会11111111
printf("%d",c);
}
printf("\ncomplemental code is ");
for (i=e+1; i>=0; i--)
{
printf("%d",d[i]);
}
printf("\n");
return 0;
}
int main() //主程序
{
int num;
printf("please input a number:\n");
scanf("%d",&num);
if (num>0) {
positive(num);
}
else if (num==0)
printf("0000000000000000\n1111111111111111\n0000000000000000");
else
negetive(num);
}
没有引入位运算会使得整个代码冗长,不过复杂无所谓,正确就可以了。
可是他不正确啊。。对于正数的输出是无问题的,一旦进入负数,其补码就会错误。
为什么呢?我们把负数for循环部分单独拎出来看一下:
num=-numb; //第一步让num重新变为1754
num=~num; //对1754求反码,此处num输出会出现-1755,原因是现在机器普遍用补码表示负数,于是求完反码之后机器直接认为此处是一个补码,就会按照补码的读取方式读取
num=num+1; //此处是对-1755+1=-1754
for (i=0; i<1000; i++) //注意此处for循环是错误的,将-1754输入进入了循环
{
d[i]=num%2; // 此处都是负数
num=num/2;
if (num>-1)
{
e=i;
break;
}
} // 因为是负数,这样一来后面输出就会出错
于是我采用位运算写法简化了二进制输出:
for(i=15;i>=0;i--) //默认16位
{
b=a>>i; //每次循环逐个读取最后一个数
b=b&~(~0<<1); //此处xcode会报警报提示未定义的左移,可以用b=b&~(~0-1)来代替
printf("%hd",b);
}
}
这串代码甚至不需要对正负数进行区分,如果是负数机器默认就是用补码储存,故直接读出来就可以了。