這幾天培訓,偶然看到這樣一道題目:
用位運算實作除法和求余運算?這一下子把不了解二進制的小白搞蒙了,
因此,查閱許多資料,寫出用位運算實作的加減乘除以及求余的代碼,附詳細思路,權當筆記,也分享給大家,
首先,我們得了解位運算子:
| 符號 | 描述 | 運算規則 |
| & | 與 | 兩個位都為1時,結果才為1 |
| | | 或 | 兩個位都為0時,結果才為0 |
| ^ | 異或 | 兩個位相同為0,相異為1 |
| ~ | 取反 | 0變1,1變0 |
| << | 左移 | 各二進位全部左移若干位,高位丟棄,低位補0 |
| >> | 右移 | 各二進位全部右移若干位,對無符號數,高位補0,有符號數,各編譯器處理方法不一樣,有的補符號位(算術右移),有的補0(邏輯右移) |
(1) 首先是&,按位與運算子,兩個位都為1時,結果才為1,
例:
2 & 3 ==> 0000 0010 & 0000 0011 = 0000 0010 即2 & 3 = 2
可見,對于十進制轉換成的二進制數,按照相應位的比對而得出結果,
(2)其次是 | ,按位或運算子,兩個位都為0時,結果才為0,
例:
2 & 3 ==> 0000 0010 | 0000 0011 = 0000 0011 即2 | 3 = 3
(3)按位異或運算子^,兩個位相同為0,相異為1,
例:
2 ^ 3 ==> 0000 0010 ^ 0000 0011 = 0000 0001 即2 ^ 3 = 1
(4)取反~,很好理解,0變1,1變成0.
例:
~3 即 0000 0011 ==> 1111 1100
(5)最后,按位左移 和 按位右移 的意思就是字面意思,
例:
3<<1 即 0000 0011 ==> 0000 0110
3<<2 即 0000 0011 ==> 0000 1100
好了,基礎知識到位,開始理論研究!
加法
我們先從加法開始,先看一個二進制加法圖:

研究1+1 可以看出,最低位滿2進1,即1 和 1 => 0 (1^1=0)
然后前進一位加上1,即 0 和 0 => 1 (應由前一位的1&1=1來獲得進位數,此時按位左移即進位)
研究2+1 可以看出,因為不需要進位,即 0 和 1 => 1
研究3+1 運用研究1+1 和 2+1的結論,可以發現只是前兩者的嵌套,
因此,我們發現,1 和 1 的運算 ,同位變成0,上一位由0變1,或由1變0
,以1+1為例,得到:

最后,代碼實作:
int Add(int a,int b)//加法位運算a+b
{
if(b)
{
return Add(a ^ b, (a & b) << 1);
}
else
{
return a;
}
}
減法
很容易想到,減法就是加上一個數的負數
而二進制負數如何得來?這里轉載一些資料:
在二進制里,最高位為符號位,用0和1 來表示正負,最高位為 1 代表負數,最高位為 0 代表正數,
負數的二進制表示分為三步:
1 把這個負數的絕對值轉換為二進制,即求原碼
2 把原碼取反,即求反碼
3 把反碼加1,即求補碼
例如把 -5 轉換為二進制,假設-5為Java中的byte型別,
bytei=5;
1 求原碼:即把-5的絕對值5轉換為二進制 為 00000101
2 求反碼:為 11111010
3 求補碼:為 11111011
來自 <計算機基礎知識 | 負數的二進制表示 - 知乎>
因此,代碼只需要將減數求反以及補碼即可
int Subt(int a, int b)//減法位運算a-b
{
return Add(a, Add(~b, 1));
}
乘法
按照小學的理解,其實就是被乘數進行乘數次的累加而已:
如:3*3 就是3+3+3
代碼實作:
int Multi(int a, int b)//乘法位運算a*b
{
int i,sum=0;
for (i=b;i>0;i--)
{
sum=Add(sum,a);
}
return sum;
}
后面轉載乘法的另一種思路:
一開始考慮到乘法其實是加法的延續,是一種累加運算,只要將被乘數進行乘數次相加即可,但這樣的做法存在一個很明顯的問題即當乘數很大時需要進行多次加法運算,下面介紹一種改進的乘法思路,這種思路由手作乘法的程序的方法而來,在進行手動乘法時,我們根據乘數的尾數是否為1來確定是否需要相加,即若乘數的尾數是1,那么就要加上被乘數,否則則不需要加上被乘數,在本次判斷之后,我們需要將被乘數左移一位,乘數邏輯右移一位,整個程序在乘數為0時停止,
同時需要注意符號的問題,這里我們首先進行絕對值的運算,再通過a^b是否小于0判斷符號的異同性,
int Multiply(int a, int b){
int a1 = a > 0 ? a : Add(~a, 1);
int b1 = b > 0 ? b : Add(~b, 1);
int sum = 0;
while(b1){
if(b1 & 0x1){
sum = Add(sum, a1);
}
a1 = a1 << 1;
b1 = b1 >> 1;
}
if((a ^ b) < 0)
return Add(~sum, 1);
else return sum;
}
轉自 位運算實作加減乘除運算——超詳細C語言描述_Pe_99y的博客-CSDN博客
除法
除法同理,即是乘法的逆運算,重復減除數,知道被除數小于除數
代碼實作:
int Divide(int a,int b)
{
int i=0;
while(a<b)
{
subt(a,b);
i++;
}
return i;
}
下面再轉載另一種思路的文章:
跟加法、減法一樣,除法是乘法的逆運算,那么除法就是做有限次的減法,直到被減數小于減數為止,這種思路類似于乘法中的簡單思路,問題同樣是在被除數遠大于除數時,需要做多次除法,
改良的除法思路如下,考慮到int型整數占32位,那么用i = 31開始比較被除數與除數的2i的大小,若被除數大,則在商處直接加上i從而減小減法的次數,
int Divide(int a, int b){
int quotient = 0;
if(!b){
cout << "Error" << endl;
return 1;
}
for(int i = 31; i --; i > 0){
if((a >> i) >= b)
{
quotient = Add(quotient, 1 << i);
a = Minus(a, b << i);
}
}
if((a ^ b) < 0)
quotient = Add(~quotient, 1);
return quotient;
}
原文鏈接:https://blog.csdn.net/qq_41716838/article/details/92193515
求余
求余即是用除法的結果乘上原除數,與被除數做差
代碼實作:
int fish(int a,int b)//求余位運算a%b
{
int c,f;
c = Divide(a,b);
f = a - (Multiply(b,c));
return f;
}
最后,我們可以進行5種運算,做開始那道題更是毫無壓力,
本文除了參考(以附原鏈接)均原創,謝謝大家支持和學習!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/342271.html
標籤:其他
上一篇:c艸進階編程(1)
