Java利用位運(yùn)算實(shí)現(xiàn)乘法運(yùn)算詳解
前言
在上一篇中,我們介紹了使用位運(yùn)算實(shí)現(xiàn)加法和減法運(yùn)算,接下來本文主要介紹如何用位運(yùn)算實(shí)現(xiàn)乘法運(yùn)算,在實(shí)現(xiàn)乘法時(shí)要用位運(yùn)算實(shí)現(xiàn),并且不能出現(xiàn)加減乘除任何符號(hào)。
之前介紹過一篇如何用位運(yùn)算實(shí)現(xiàn)加法和減法: 如何用位運(yùn)算實(shí)現(xiàn)加減運(yùn)算?
正文
在用位運(yùn)算實(shí)現(xiàn)之前,我們先來回憶一下小學(xué)時(shí),學(xué)乘法時(shí)用的十字相乘法。
十進(jìn)制相乘
例如,26 * 15,在進(jìn)行乘法操作時(shí),我們一般這樣算,先用5乘以6得到30,把0寫下把3記在一邊,再用5乘以2得到10再加上之前的3寫在下面,得到130;計(jì)算完5再計(jì)算1分別乘以6和2把得到的結(jié)果26記在下面,然后把130和26相加(有錯(cuò)位)得到390。

二進(jìn)制相乘
看完了十進(jìn)制的相乘,再來看下二進(jìn)制的相乘,基本原理是一樣的,也是以十字相乘法為例,計(jì)算 5 * 7。
5的二進(jìn)制為101,7的二進(jìn)制為111,來看下二進(jìn)制的十字相乘法。

可以看到二進(jìn)制為101和二進(jìn)制111用傳統(tǒng)的方式來計(jì)算,得到的結(jié)果為100011,而二進(jìn)制100011對應(yīng)的十進(jìn)制為35。
所以說,在計(jì)算的過程中,十進(jìn)制和二進(jìn)制的計(jì)算方式是一樣的,當(dāng)然這里就不進(jìn)行舉例和證明了。
思路分析
既然計(jì)算過程有了,那么怎么樣用代碼來實(shí)現(xiàn)呢?
我們再來看下上圖中二進(jìn)制的計(jì)算過程:
- 先用二進(jìn)制
111的最后一位1乘上101得到101。 - 再用二進(jìn)制
111的倒數(shù)第2位1乘上101得到101。 - 再用二進(jìn)制
111的倒數(shù)第3位1乘上101得到101。 - 得到的三個(gè)
101進(jìn)行二進(jìn)制相加,得到100011。
注意,第2步和第3步得到的結(jié)果101都往前挪了一位,相當(dāng)于1010和10100,也就是最后相加的計(jì)算為:10100 + 1010 + 101 = 100011。
再來看得到最終相加的計(jì)算10100 + 1010 + 101 = 100011,也就是只要我們找到如何把數(shù)據(jù)轉(zhuǎn)換為幾位數(shù)的相加就可以了,因?yàn)橹耙呀?jīng)實(shí)現(xiàn)了如何用位運(yùn)算實(shí)現(xiàn)加法操作。
這三個(gè)數(shù)101、1010、10100的數(shù)量剛好與二進(jìn)制111的個(gè)數(shù)相同,也就是二進(jìn)制(上圖下面那個(gè)乘數(shù)111)有幾位就會(huì)產(chǎn)生幾個(gè)數(shù)相加,如果是與11111相乘就會(huì)產(chǎn)生5個(gè)數(shù)相加。
再來看數(shù)據(jù)之前的關(guān)系:
- 第一次相乘結(jié)果:
101 = 101 + 0 - 第二次相乘結(jié)果:
1111 = 101 < 1 + 101 = 1010 + 101 - 第三次相乘結(jié)果:
100011 = 101 < 2 + 1111 = 10100 + 1010 + 101
從這里我們可以看到,每計(jì)算一次,101只需要向左移一次再加上上一次的計(jì)算結(jié)果就可以了。
那么,怎么知道要左移多少次呢?從這里例子中看,111每次計(jì)算后,向右移動(dòng)一次,101也跟著向左移動(dòng)一次,直到111只剩最后一位,則停止計(jì)算就好了。
代碼實(shí)現(xiàn)
根據(jù)上面的思路,來實(shí)現(xiàn)一下代碼:
// 用位運(yùn)算實(shí)現(xiàn)加法
public static int add(int a, int b) {
int sum = 0;
while (b != 0) {
sum = a ^ b;
b = (a & b) << 1;
a = sum;
}
return sum;
}
// 用位運(yùn)算實(shí)現(xiàn)減法
public static int multi(int a, int b) {
int res = 0;
while (b != 0) {
if ((b & 1) != 0) {
res = add(res, a);
}
a <<= 1;
b >>>= 1;
}
return res;
}運(yùn)行一下代碼,看下結(jié)果:

可以看到計(jì)算是正確的,而且還支持負(fù)數(shù)。
總結(jié)
本文介紹了如何用純位運(yùn)算實(shí)現(xiàn)乘法的運(yùn)算,并介紹了實(shí)現(xiàn)思路以及分析,需要注意的是,位運(yùn)算右移的時(shí)候需要使用無符號(hào)右移,否則的話,會(huì)出現(xiàn)死循環(huán)的。
另外,本文只是介紹利用位運(yùn)算來實(shí)現(xiàn)乘法的實(shí)現(xiàn)過程、知識(shí)點(diǎn)的介紹,雖然是使用的位運(yùn)算但是效率是不能和Java原生的加法運(yùn)算相比的,并沒有原生的效率高。
到此這篇關(guān)于Java利用位運(yùn)算實(shí)現(xiàn)乘法運(yùn)算詳解的文章就介紹到這了,更多相關(guān)Java位運(yùn)算實(shí)現(xiàn)乘法運(yùn)算內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot登錄攔截器+ThreadLocal實(shí)現(xiàn)用戶信息存儲(chǔ)的實(shí)例代碼
ThreadLocal 為變量在每個(gè)線程中創(chuàng)建了一個(gè)副本,這樣每個(gè)線程都可以訪問自己內(nèi)部的副本變量,這篇文章主要介紹了springboot登錄攔截器+ThreadLocal實(shí)現(xiàn)用戶信息存儲(chǔ)的實(shí)例代碼,需要的朋友可以參考下2024-03-03
SpringBoot整合redis+Aop防止重復(fù)提交的實(shí)現(xiàn)
Spring Boot通過AOP可以實(shí)現(xiàn)防止表單重復(fù)提交,本文主要介紹了SpringBoot整合redis+Aop防止重復(fù)提交的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
SpringBoot中實(shí)現(xiàn)Druid前端監(jiān)控界面自動(dòng)登錄功能
這篇文章主要介紹了SpringBoot中實(shí)現(xiàn)Druid前端監(jiān)控界面自動(dòng)登錄功能,需要的朋友可以參考下2024-08-08
Java中實(shí)現(xiàn)日志記錄的方案總結(jié)
在平時(shí)使用到一些軟件中,比如某寶或者某書,通過記錄用戶的行為來構(gòu)建和分析用戶的行為數(shù)據(jù),這就需要使用到日志系統(tǒng)來存儲(chǔ)或者記錄數(shù)據(jù),小編為大家整理了幾種Java日志方案,希望對大家有所幫助2024-12-12
基于FLink實(shí)現(xiàn)實(shí)時(shí)安全檢測的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何基于FLink實(shí)現(xiàn)實(shí)時(shí)安全檢測的功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的可以了解一下2023-02-02
java數(shù)據(jù)結(jié)構(gòu)排序算法之樹形選擇排序詳解
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)排序算法之樹形選擇排序,結(jié)合具體實(shí)例形式分析了java樹形選擇排序的原理、實(shí)現(xiàn)技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-05-05
Resty開發(fā)restful版本的Jfinal深入研究
這篇文章主要為大家介紹了Resty開發(fā)restful版本的Jfinal深入研究有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03

