今天在做一道关于将一个数的二进制模式从左到右翻转时引发了一些思考,于是就赶紧记录下来,方便日后查看。原题是编写一个函数:这个函数返回一个输入值value的二进制位模式从左到右翻转后的值。题目本身并不难,但是即使是再小的题目也有它存在的意义。每道题目都能教会我们一些知识。
首先是方法:最容易想到也是一般最先想到的是定义一个arr[32]的数组。将输入值value每次对2取余,然后将余数依次从数组的第一位开始存放,接着将每一位乘上位权后相加,最后返回结果。当然转念一想其实根本用不到数组,只要将余数乘上它移位之后的位权即可,然后相加。当然方法是无穷无尽的。
我的想法是首先定义一个存放最后的值的变量sum并初始化为0,value&1(取它最后一位的数字),然后sum或等上(value&1),接着value的值每次右移一位,当然sum也要每次左移一位,但是写在什么位置合适呢?开始我习惯性的写在后面,但是程序出现了问题。结果是错误的。
现附上我最初写的:
<span style="font-size:18px;">#include<stdio.h>
#include<math.h>
unsigned int reverse_bit(unsigned int value)
{
int i;
unsigned int sum = 0;
unsigned int num = value;
for ( i = 0; i < 32; i++)
{
sum |= (num&1);
sum <<= 1;
num >>= 1;
}
return sum;
}
int main()
{
unsigned int number = 0;
unsigned int ret = 0;
printf("请输入一个数字\n");
scanf("%d",&number);
ret = reverse_bit(number);
printf("翻转后的值为:%u",ret);
return 0;
}</span>
程序看上去没什么问题,但是结果却是错的,后来看了半天,发现把一个32位的二进制数字拿下来只需要31次移动就可以了,而上面的程序循环换了32次,所以所得到的结果会比原来多1倍。答案也就错了,很容易就会想到是不是把循环次数32改成31就行了呢?
改成31之后:
改了之后试了几个数字确实答案是正确的。但是整个程序却出现了逻辑问题,首先就是最高位也就是第32位的值永远也拿不到了,程序也就是错误的程序。因此必须要让它浪费一次位移的次数。所以将程序稍加修改即可:让它先执行右移,再去执行其他的步骤。
<span style="font-size:18px;">#include<stdio.h>
#include<math.h>
unsigned int reverse_bit(unsigned int value)
{
int i;
unsigned int sum = 0;
unsigned int num = value;
for ( i = 0; i < 32; i++)
{
sum <<= 1;
sum |= (num&1);
num >>= 1;
}
return sum;
}
int main()
{
unsigned int number = 0;
unsigned int ret = 0;
printf("请输入一个数字\n");
scanf("%d",&number);
ret = reverse_bit(number);
printf("翻转后的值为:%u",ret);
return 0;
}</span>
这样程序才是对的,哪怕数字变大了,答案也是对的。