假设X为一个int型变量,请给出一个用来计算x/32的值的函数div32.要求不能使用除法、
乘法、模运算、比较运算、循环语句和条件语句。
可以使用右移、加法以及按位运算。
#include<iostream>
using namespace std;
void div32(int n)
{
int x=(n>>31)&0x1F; //偏置常数
int ans=(n+x)>>5;
cout<<ans<<endl;
}
int main()
{
div32(64);
return 0;
}
这里注意,这个函数是设计用于整除
如果不是整除的话,结果按照C语言的整除规则——只保留整数部分
特别注意!!
要实现C语言的整除规则的话则引入一个偏置常数是必要的!
不然如下:
#include<iostream>
using namespace std;
int main()
{
int n=-3>>1;
cout<<n<<endl;
return 0;
}
执行结果:
-2
请按任意键继续. . .
当被除数是负数且不能整除时,就会出现错误
有人可能会想,加个 if 去判断啊
但是,题目说了不能用条件语句!
所以,还是得引入偏置常数,下面具体来看看偏置常数是如何得来的
如果大家多测几个数据,就会发现,如果直接进行位移操作,误差只是1而已
这个“1”,其实可以看作是该数的机器码向右位移后数值位的最后一位
-3的机器码——1…1101
向右位移1位——1…110—— -2
要修复那个BUG的话,只要设置好什么条件下给数值位最后一位进一位就OK了
那么究竟是什么条件下呢?
其实,这个条件就是是否整除
下面拿除以4简单分析一下
拿八位的机器码来看
0000 0100 ——真值:4
大家可以发现,往1左边走,分别是8, 16, 32 …
这些左边的数字完全可以除以4,也就是说不会出现除不尽4的情况
主要是1右边的数—— 2,1
举个例子:
0000 0110—— 6 除不尽4
那么,规律就已经出来了~
是否可以被4整除,就看4在机器码中对应的数位右边是否有值
若没有,则可以整除
若有,则不能整除
现在看到刚刚给出的-3的例子
-3 的机器码——1…101
除以2,则看2对应的数位——倒数第二位的右边
有1——不能整除
则要在位移后加一
1…10+1 = 1…11
即为-1 ——加了1才是正确的
回到除以32的题目
int x=(n>>31)&0x1F; //偏置常数
其实,这一个偏置常数为什么这么设置的答案已经出来了
x=11111=31(n为负数)
x=00000=0(n为正数)
int ans=(n+x)>>5;
可以发现,偏置常数11111则是机器码的末尾5位——对应除数32
n+x——只要n机器码的末尾5位中存在一个1,则这个加法会实现前面提到的——“加一”
——在位移后数值位的最后一位加一
以上!解析完毕~