Java利用位運(yùn)算實(shí)現(xiàn)加減運(yùn)算詳解
前言
本文主要介紹如何使用位運(yùn)算來實(shí)現(xiàn)加減功能,也就是在整個(gè)運(yùn)算過程中不能出現(xiàn)加減符號(hào)。
加減乘除運(yùn)算在計(jì)算機(jī)中,實(shí)際上都是用位運(yùn)算實(shí)現(xiàn)的,今天就用位運(yùn)算來模擬下加法和減法的運(yùn)算功能。
思路分析
先分析如何用位運(yùn)算實(shí)現(xiàn)加法運(yùn)算。
示例
假設(shè)a=23
,b=36
,使用位運(yùn)算實(shí)現(xiàn)加法得到結(jié)果59
。
首先來看下23
、36
、59
的二進(jìn)制信息。
從上面的圖中可以看到,兩個(gè)數(shù)相加的結(jié)果與兩個(gè)數(shù)異或的結(jié)果很相似,只不過在圖中的2位置相加的時(shí)候,產(chǎn)生了進(jìn)位,而異或是沒有進(jìn)位的,如果能拿到進(jìn)位信息,把兩個(gè)數(shù)異或的結(jié)果和進(jìn)位信息的結(jié)果相加就能得到最終結(jié)果了,那么如果能拿到進(jìn)位信息呢?
位運(yùn)算進(jìn)位
上圖中,59
的二進(jìn)制信息可以分為兩部分,0110011
和 0001000
,再結(jié)合23
、36
的二進(jìn)制信息來看,0110011
為23
和36
的異或結(jié)果,而23
和36
相與的結(jié)果跟0001000
很相似,只不過0001000
中的1
比相與結(jié)果往前移了一位。
于是,我們可以得出,兩個(gè)數(shù)的二進(jìn)制進(jìn)位信息為兩個(gè)數(shù)的相與在左移一位。
初步結(jié)果
經(jīng)過上面的分析,我們可以得到了一個(gè)初步的運(yùn)算結(jié)果,即兩個(gè)數(shù)相加等于兩個(gè)數(shù)異或加上兩個(gè)數(shù)的相與左移1位,也就是a + b = (a ^ b) + ((a & b) << 1)
。
先用23
和36
來驗(yàn)證下。
經(jīng)過驗(yàn)證可以看到,剛才得出的結(jié)論是正確的。
但是,我們要做到在整個(gè)運(yùn)算過程中不能出現(xiàn)加號(hào),接下來要想辦法把這個(gè)加號(hào)給去掉。
去除加號(hào)
還是以23
和36
為例,經(jīng)過上面的運(yùn)算我們把運(yùn)算的位運(yùn)算結(jié)果給化簡(jiǎn)下。
23 + 36 = (23 ^ 36) + ((23 & 36) << 1) = 51 + 8
也就是把23
和36
的相加運(yùn)算轉(zhuǎn)化為了51
和8
的相加運(yùn)算,接下來繼續(xù)分析51
和8
的相加運(yùn)算,也是通過異或和相與進(jìn)行操作。
51 + 8 = (51 ^ 8) + ((51 & 8) << 1) = 59 + 0
嗯?可以發(fā)現(xiàn)我們已經(jīng)得出59
了,而且還加了個(gè)0
,加了個(gè)0
不就相當(dāng)于加了個(gè)寂寞嘛,可以直接省略啊。
由此,我們又可以得出一個(gè)結(jié)論,兩個(gè)數(shù)的二進(jìn)制進(jìn)位信息為兩個(gè)數(shù)的相與在左移一位,不停地循環(huán)這個(gè)過程,直到有一個(gè)數(shù)變?yōu)?,就能得到結(jié)果。
整體思路
現(xiàn)在來總結(jié)下整體的計(jì)算過程:
- 把兩個(gè)數(shù)相加,拆分成兩步,兩個(gè)數(shù)異或加上兩個(gè)數(shù)相與左移1位。
- 判斷相與左移的結(jié)果是否為0。
- 如果相與左移為0,兩個(gè)數(shù)異或的結(jié)果即為相加的結(jié)果。
- 如果相與左移結(jié)果不為0,把得到的新結(jié)果,重復(fù)執(zhí)行第1~3步操作。
加法代碼實(shí)現(xiàn)
經(jīng)過上面的分析,來看下代碼實(shí)現(xiàn)。
public class Code19_Add { 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; } public static void main(String[] args) { int sum = add(23, 36); System.out.println(sum); } }
運(yùn)行程序,輸出結(jié)果為59。
減法實(shí)現(xiàn)
減法分析
還是以23
和36
為例,如果要計(jì)算 36 - 23
,該怎么辦?
36 - 23
不就相當(dāng)于36 + (-23)
,可以理解為加上一個(gè)負(fù)數(shù),這就可以了嗎?不不不,要求的是不能出現(xiàn)加減符號(hào),-23
里面是有減法這個(gè)符號(hào)的。
還記得前面我們分析的負(fù)數(shù)可以怎么表示嗎?對(duì)了,負(fù)數(shù)是對(duì)一個(gè)數(shù)的取反再加1。嗯?又出現(xiàn)加號(hào)了,不過加法我們不是已經(jīng)實(shí)現(xiàn)了嗎?直接拿來用就好了。
減法代碼實(shí)現(xiàn)
有了加法操作,減法就很簡(jiǎn)單了,來看下代碼。
public class Code20_Sub { 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; } public static int sub(int a, int b) { return add(a, add(~b, 1)); } public static void main(String[] args) { int sum = sub(36, 23); System.out.println(sum); } }
運(yùn)行一下輸出結(jié)果為13
。
嗯,Perfect!
總結(jié)
本文主要介紹如何使用位運(yùn)算來實(shí)現(xiàn)加減功能,至此功能都已經(jīng)實(shí)現(xiàn)了。
那么問題來了,我們實(shí)現(xiàn)的加減運(yùn)算與Java本身的加減相比,誰的效率更高呢?當(dāng)然是Java中的更高了,因?yàn)槲覀兪怯肑ava實(shí)現(xiàn)的,代碼運(yùn)行后,要經(jīng)過層層的翻譯才能到達(dá)底層,所以效率肯定是有損失的。
當(dāng)然我們的目的是熟悉位運(yùn)算的操作,這個(gè)才是最重要的。
到此這篇關(guān)于Java利用位運(yùn)算實(shí)現(xiàn)加減運(yùn)算詳解的文章就介紹到這了,更多相關(guān)Java位運(yùn)算實(shí)現(xiàn)加減運(yùn)算內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Intellij IDEA中.properties文件中文顯示亂碼問題的解決
這篇文章主要介紹了詳解Intellij IDEA中.properties文件中文顯示亂碼問題的解決,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11java正則表達(dá)式匹配規(guī)則超詳細(xì)總結(jié)
正則表達(dá)式并不僅限于某一種語言,但是在每種語言中有細(xì)微的差別,下面這篇文章主要給大家介紹了關(guān)于java正則表達(dá)式匹配規(guī)則的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10Mybatis中BindingException異常的產(chǎn)生原因及解決過程
BindingException異常是MyBatis框架中自定義的異常,顧名思義指的是綁定出現(xiàn)問題,下面這篇文章主要給大家介紹了關(guān)于MyBatis報(bào)錯(cuò)BindingException異常的產(chǎn)生原因及解決過程,需要的朋友可以參考下2023-06-06SpringBoot整合Redis實(shí)現(xiàn)刷票過濾功能
隨著互聯(lián)網(wǎng)的不斷發(fā)展,網(wǎng)站或APP的用戶流量增加,也衍生出了一些惡意刷量等問題,給數(shù)據(jù)分析及運(yùn)營(yíng)帶來極大的困難,所以本文使用SpringBoot和Redis實(shí)現(xiàn)一個(gè)刷票過濾功能,需要的可以參考一下2023-06-06java多線程之Future和FutureTask使用實(shí)例
這篇文章主要介紹了java多線程之Future和FutureTask使用實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09spring boot springMVC擴(kuò)展配置實(shí)現(xiàn)解析
這篇文章主要介紹了spring boot springMVC擴(kuò)展配置實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08SpringBoot前后端分離實(shí)現(xiàn)個(gè)人博客系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了使用springboot+mybatis+前端vue,使用前后端分離架構(gòu)實(shí)現(xiàn)的個(gè)人博客系統(tǒng),感興趣的小伙伴可以動(dòng)手嘗試一下2022-06-06