老婆餅裡沒老婆之用位運算實現加減乘除

2021-02-19 程式設計師木頭的悲慘生活

眾所周知,老婆餅裡是沒有老婆的,夫妻肺片是裡沒有夫妻的,那麼四則運算中可以沒有 +、-、×、÷ 這四個運算符嗎?當然是可以的。本文會先從基礎知識介紹起,再通過代碼實現,最後,我們還可以探討一下計算機運算器的起點及其哲學。

1. 位運算實現四則運算的原理及其基礎知識1.1 原碼、反碼與補碼

眾所周知,計算機的世界是由 0 和 1 組成的,我們平時也會稱其為一個「二進位」的世界。一個數在計算機中的二進位表示,叫作這個數的機器數,其中,最高位表示該數的符號,正數為 0,負數為 1。另外,我們也將帶有符號位的機器數對應的真正數值稱為機器數的真值

原碼(true form):原碼就是我們上段提到的真值的概念。直觀點講,例如,用 8 位二進位表示一個數,+11 的原碼為 0,0001011,-11 的原碼為 1,0001011。

反碼(Inverse code):機器數是正數時,反碼和原碼是一樣的;為負數時,反碼就是原碼除符號位外,其他位按位取反。直觀來說,+0 和 -0 的反碼,+0 的原碼是 0,0000000 ,則反碼為 0,0000000;-0 的原碼為 1,0000000,則反碼為 1,1111111 。

補碼(two's complement representation):在計算機系統中,數值一律用補碼來表示和存儲(請記住這一點)。原因在於,使用補碼,可以將符號位和數值域統一處理;同時,加法和減法也可以統一處理。

介紹完三者的概念,我們來演示一下,補碼是怎麼計算得來的。

首先,我們要先介紹一下「模」的概念:「模」是指一個計量系統的計數範圍,如過去計量糧食用的鬥、時鐘等。計算機也可以看成一個計量機器,因為計算機的字長是定長的,即存儲和處理的位數是有限的,因此它也有一個計量範圍,即都存在一個「模」。如:時鐘的計量範圍是0~11,模=12。表示n位的計算機(32位,64位)計量範圍是 0~2^n -1,模即為 2^n 。「模」實質上是計量器產生「溢出」的量,它的值在計量器上表示不出來,計量器上只能表示出模的餘數。任何有模的計量器,均可化減法為加法運算。

假設當前時針指向8點,而準確時間是6點,調整時間可有以下兩種撥法:一種是倒撥2小時,即8-2=6;另一種是順撥10小時,8+10=12+6=6,即8-2=8+10=8+12-2(mod 12)。在12為模的系統裡,加10和減2效果是一樣的,因此凡是減2運算,都可以用加10來代替。若用一般公式可表示為:a-b=a-b+mod=a+mod-b。對「模」而言,2和10互為補數。實際上,以12為模的系統中,11和1,8和4,9和3,7和5,6和6都有這個特性,共同的特點是兩者相加等於模。對於計算機,其概念和方法完全一樣。n位計算機,設n=8,所能表示的最大數是11111111,若再加1成100000000(9位),但因只有8位,最高位1自然丟失。又回到了 00000000,所以8位二進位系統的模為 2^8 。在這樣的系統中減法問題也可以化成加法問題,只需把減數用相應的補數表示就可以了。把補數用到計算機對數的處理上,就是補碼。即計算機中的 a-b 等於 a 加上 b 的補碼。

原碼求補碼,以及補碼求原碼,大家感興趣的話可以自己手動算一下,這裡直接給結論。

1.1.1 原碼求補碼

正數:正數的補碼與原碼相同。

負數:負數的補碼,將其原碼除符號位外的所有位取反(0變1,1變0,符號位為1不變)後加1。

1.1.2 補碼求原碼

⑴如果補碼的符號位為「0」,表示是一個正數,其原碼就是補碼。

⑵如果補碼的符號位為「1」,表示是一個負數,那麼求給定的這個補碼的補碼就是要求的原碼,即除符號位外取反後加1。

1.2 四則(加減乘除)運算的原理1.2.1 加法

加法是運算中最簡單的一個。小學我們學的加法,都是十進位的,個位加個位,十位加十位,逢十進位,各個位上的數值再加上進位就得到了結果,「和」。同理,計算機二進位的世界也是一樣的,無非是 1 + 0 = 1,1 + 1 = 0,0 + 0 = 0,逢 2 進位。學過邏輯運算的應該都知道,前面的這種等式可以使用 「異或」 來進行實現,運算符為 ^,也是計算機中位運算的一種,然後再記錄進位就可以了。

1.2.2 減法

既然解決了加法,那麼減法就很容易了,a - b = a + (-b),而上面提到的補碼的知識在這裡就有用了,求 b 的反碼加1 即為 -b 的補碼。這裡我們用到的運算為取反,位運算符為 ~b

1.2.3 乘法

乘法的含義即為被乘數個乘數相加,說白了還是加法。

1.2.4 除法

除法的含義即為不停地用除數去減被除數,直到被除數小於除數時,此時所減的次數就是我們需要的商,而此時的被除數就是餘數。

代碼實現

了解完基本原理,寫代碼就是很簡單的事了。註:這裡的代碼只是簡單地實現了一下原理,感興趣的同學可以寫出更優的代碼,也可以使用其他語言實現一下。

1. 加法
   /**
* 實現 a + b
*
* @param a
* @param b
* @return a 與 b 和
*/
public static int add(int a, int b) {
int sum = 0;
// 進位
int carry;
while (b != 0) {
sum = a ^ b;
// 對應位和的進位,既然是進位,就要整體左移一位
carry = (a & b) << 1;
a = sum;
b = carry;
}
return sum;
}

2. 減法
    /**
* 實現 a - b,其實就是 a + (-b)
*
* @param a
* @param b
* @return a - b 的差
*/
public static int subtract(int a, int b) {
// 引入 c = -b
int c = add(~b, 1);

return add(a, c);
}

3. 乘法
   /**
* 實現 a * b,即將被乘數累加乘數次得到的結果,先計算絕對值累加,再求符號
*
* @param a
* @param b
* @return
*/
public static int multiply(int a, int b) {
// 將乘數和被被乘數都取絕對值
int multiplier = a < 0 ? add(~a, 1) : a;
int multiplicand = b < 0 ? add(~b, 1) : b;

// 計算絕對值的乘積
int product = 0;
int count = 0;

while (count < multiplier) {
product = add(product, multiplicand);
count = add(count, 1);
}

// 計算乘積的符號
if ((a ^ b) < 0) {
product = add(~product, 1);
}
return product;
}

4. 除法
    /**
* 計算 a / b 的值,即不停地用除數去減被除數,直到被除數小於除數時,此時所減的次數就是我們需要的商,而此時的被除數就是餘數。注意符號。
*
* @param a
* @param b
* @return
*/
public static int divide(int a, int b) {
// 對被除數和除數去絕對值
int dividend = a < 0 ? add(~a, 1) : a;
int divisor = b < 0 ? add(~b, 1) : b;

// 對被除數和除數的絕對值求商
int remainder = dividend;
int quotient = 0;

while (remainder >= divisor) {
remainder = subtract(remainder, divisor);
quotient = add(quotient, 1);
}

// 求商的符號
if ((a ^ b) < 0) {
quotient = add(~quotient, 1);
}

return quotient;
}

「抽象」與「封裝」

從上面的代碼我們可以看出,當有了加法之後,減法、乘法、除法皆可以在之前的基礎上完成運算,這裡我們還可以抽離出幾個方法,比如,求一個數的相反數:

//求a的相反數:將各位取反加一
int negative(int a) {
return add(~a, 1);
}

這樣,減法的代碼就可以寫作:

    public static int subtract(int a, int b) {
return add(a, negative(b));
}

是不是比之前的代碼簡潔了許多。我們把求反碼的過程「封裝」成一個函數,然後將這個函數「抽象」為取相反數,這樣我們就可以忽略封裝的內容,直接使用抽象出來的方法就可以了。就像我們首先封裝了加法,其他運算也是直接使用加法的函數,而不去深究加法具體是怎麼實現的,這就是 抽象 的好處和魅力,它讓我們不用去管底層細節,把精力用來構建更複雜的系統。

眾所周知,假如你知道的話,計算機硬體上由控制器、運算器、存儲器、輸入輸出設備組成,其硬體實現也從最開始的繼電器、真空管,再到電晶體,計算機內部電路的複雜程度和計算能力可能遠超過我們的想像。不過,再複雜的東西也都是由最簡單的組件構成的,小組件可以構成大一點的組件後,大一點的組件可以組成更大的組件,其思想就是利用 「抽象」 和 「封裝」 來降低我們對於複雜度的認知。至少在計算機和軟體工程領域如此,如果你跟我說畢卡索的 「抽象」 藝術,那當我沒說。

那麼想必你也知道,電路中有電流流過,我們就把它認為是「1」,也可以表示為 「true」,電路中沒有電流流過,我們就把它認為是「0」,也可以表示為 「false」,那麼該如何來表示和計算呢?在數學領域,有一整個數學分支,專門處理「真」和「假」,而且它已經解決了所有法則和運算,稱為「布爾代數」(Boolean Algebra)!與常規的計算不同,布爾代數的運算並不是加減法,而是邏輯運算,其中有三個基本的邏輯運算:NOT 、AND 和 OR。

NOT:NOT 運算有一個輸入,一個輸出,輸入為 true 時,輸出 false;輸入為 false 時,輸出為 true。我們可以列出其「真值表」以及畫出其電路實現。

AND:AND 運算有兩個輸入,必須兩個輸入都為 true,輸出才為 true;否則,輸出為 false。

OR:OR 運算也有兩個輸入,當兩個輸入有其中一個為 true 時,輸出便為 true;否則,輸出則為 false。

接著,我們可以進行一次抽象。可以將 NOT 門電路、AND 門電路、OR 門電路抽象成如下符號,電路本身的電晶體和電線還是在的,只是換了一種表現方式:

然後我們就可以用這些抽象出來的符號,構建更大的組件,而且也不會變更很複雜。比如,我們可以用來構建另外一個很重要的布爾操作,「異或」(XOR-Exclusive OR),代碼裡的位運算符為 ^ ,就是我們實現加法的那個。其真值表為:

以及我們可以按照下面的步驟通過其他的邏輯門電路實現一個異或的電路:

然後我們可以再進行一次抽象,將異或用下面的符號表示:

這樣,我們就可以把 「異或」 放入工具箱,下一次便可直接使用它來構建其他組件,而不用顧慮 XOR 具體用了幾個門電路,以及這幾個門電路又是怎麼用電晶體拼的,電子是怎麼流過半導體的。

總結

本文先是不用 + 、- 、× 、÷ 四種符號實現了簡單的四則運算,來說明了計算機底層是如何完成計算這一任務的。之後又簡單介紹了一下邏輯運算,與邏輯門電路的實現,給大家初步展示了一下計算機中 「抽象」 的藝術。總之,在抽象的基礎之上,計算機工程師在設計處理器時,很少會在電晶體層面上思考,而是用更大的組件思考,比如邏輯門什麼的;開發工程師在開發功能時,也極少會考慮邏輯是怎樣在物理層面實現的,而是會專注於業務邏輯實現。以致於當前最流行的 Serverless 、Faas 等等雲計算相關的技術,大多也得益於這種思想。希望大家也會有所啟發。

連結

•用基本位運算實現加減乘除:https://www.cnblogs.com/kiven-code/archive/2012/09/15/2686922.html•相關代碼(Java 版):https://github.com/lq920320/algorithm-java-test/blob/master/src/test/java/other/calculator/Calculator.java•【計算機科學速成課】:https://www.bilibili.com/video/BV1EW411u7th•阮一峰 XOR 教程:https://mp.weixin.qq.com/s/dVOyUMaJRRIsND0yz4Llvg

相關焦點

  • 菠蘿包裡沒菠蘿,老婆餅裡沒老婆,我可能吃了一個假香港...
    老婆餅跟老婆有什麼關係? 如果你真的信了這些字面上的意思就太naïve了,香港美食裡有大把大把的大屁眼子,今天圈妹就要帶你們來「打假」! 菠蘿包的誕生還得益於「港人是吃貨」這個人設。賣有菠蘿的菠蘿包——樂香園沒吃過老婆餅也看過港劇吧,TVB裡動不動就喜歡去元朗買老婆餅,在《憨夫成龍》這部劇裡,老婆餅還變成了男主角為愛吃糖冬瓜的老婆
  • 位運算就能做到,就不要寫那麼多代碼了【位運算奇淫技巧】
    這種就屬於排列組合的問題了,對於每個物品(位置)來說,就是使用和不使用的兩個狀態,而在二進位中剛好可以用1和0來表示。而在實現上,通過枚舉數字範圍分析每個二進位數字各符號位上的特徵進行計算求解操作即可。
  • 老婆餅可以沒老婆,但是一定要好吃!
    相傳一位廣州的點心師傅回老家潮州探親時,給家人帶了很多廣州點心,但他老婆吃了卻說:「這些廣州名點還沒有我做的冬瓜角好吃呢。」這位師傅不信,他老婆便以冬瓜蓉為餡、麵粉為皮,做了些冬瓜角給他吃,他覺得確實好吃,回廣州前讓老婆又做了一大包,帶到廣州給其他師傅品嘗,沒想到大家吃了之後都連聲道好。由於這點心是師傅的潮州老婆所做,大家便叫它潮州老婆餅。
  • 【Buy】老婆餅裡沒老婆 神仙水裡沒神仙
    「神仙水裡有神仙嗎?」「老婆餅裡有老婆嗎?」神仙水跟其他所有水一樣,裡當然沒有什麼神仙和救世主。只有一些可能會產生改變的,「PITERA™——活性酵母精華」(啊輸入法好高級!居然可以打出來這個!)收到這瓶限量水的時候手頭的330ml只剩不到一半,急缺安全感。正愁如何囤貨時,就雪中送炭。
  • 老婆餅裡有老婆的囧圖
    老婆餅裡拼老婆的囧圖 姿勢不對,再踢高點 我也知道《古惑仔》是漫畫改編,但沒想到漫畫居然才剛剛要大結局?得想個辦法讓我閨蜜看到這條新聞…總覺得店員有點眼熟代表nerv懲罰你!老婆餅裡拼老婆的囧圖 2020-05-01 18:38 網際網路
  • 菜譜 | 老婆餅為什麼叫老婆餅?
    老婆餅的起源有多個傳說,其中一個說法是古時一對窮苦夫婦,妻子把冬瓜做成蓉作餡製成圓形餅,並由丈夫在街市售賣,大受歡迎。丈夫便將餅命名「老婆餅」以感謝妻子。老婆餅的由來另有一說,在從前,有個老婆因為公公生病了,家裡沒錢替公公治病,所以自願賣身為奴,深愛老婆的老公為了贖回妻子,努力研發了一種美味可口的餅,並且靠著賣餅的錢將妻子贖回,於是,後來的人就將這種餅稱為老婆餅。
  • 沒有老婆的老婆餅是這樣製作的~
    其實老婆餅就是用麵粉、糯米粉、食用油等食材做的餅,不藉助任何添加劑和特殊的工具,就能達到香酥掉渣的效果。
  • 做好改革「加減乘除」四則運算 不斷提升司法效能 ——蔡甸法院...
    蔡甸法院作為民事訴訟程序繁簡分流改革試點法院之一,該院緊緊圍繞五項改革重點內容,做好改革「加減乘除」四則運算,著力優化訴訟前端司法資源配置,進一步加強「兩個一站式」建設,鞏固運用「道交一體化」改革成果,探索完善速裁快審程序,著力推動構建分層遞進、繁簡結合、銜接配套的多元解紛機制,提升司法效能,
  • 龜苓膏裡真的有烏龜嗎?老婆餅裡雖然沒有老婆,但龜苓膏裡真的有龜!
    龜苓膏裡真的有烏龜嗎?老婆餅裡雖然沒有老婆,但龜苓膏裡真的有龜!時間:2020-10-04 10:23   來源:鬥玩網    責任編輯:沫朵 川北在線核心提示:原標題:龜苓膏裡真的有烏龜嗎?老婆餅裡雖然沒有老婆,但龜苓膏裡真的有龜!
  • 真的有老婆的老婆餅C位出道!一口酥到你心裡!
    說起老婆餅,很多年輕人都搖搖頭,表示沒興趣口味單調,一成不變,口感欠佳出品參差不齊,用料和做法越來越敷衍最慘的是,愛吃老婆餅還不一定找得到老婆然而這款網紅新派老婆餅卻C位出道10層酥皮點心郎老婆餅的創始人陳師傅是一個浪漫的人他就足足用了7年的時間研究老婆餅還因為這個新派老婆餅而抱得美人歸!
  • 老婆餅因何而得名
    相傳在廣州,有一間創辦於清朝末年的老字號茶樓,以各式點心及餅食馳名;某日,茶樓裡一位來自潮州的點心師傅,帶了店裡各式各樣的招牌茶點回家給老婆吃,想不到他老婆吃了之後,不但沒稱讚店裡的點心好吃,甚至還嫌棄地說:「茶樓的點心竟是如此平淡無奇
  • 【小說】王乾:老婆餅
    他靜靜地坐在客廳裡,隨手點燃了一支香菸,就看見妻子在廚房裡忙個不停。生活依舊如靜水一般的平靜,可他的身體卻大不如前了,思想慢慢地變了,就口味也悄然地發生著改變。他有時在想,也許世界上根本就沒有一成不變的東西,包括婚姻觀,人生價值觀。他吐著煙圈,煙霧瀰漫,禁不住連連咳嗽幾聲。他就弄不明白了,原來最愛吃的老婆餅,現在怎麼也吃不出那種味道來。
  • 老婆餅裡沒老婆,可樂餅裡也沒可樂.這道口感和營養滿分的健康零食,寶寶愛了!
    燃鵝……就像老婆餅裡沒有老婆一樣,可樂餅裡也沒有可樂。可樂餅 是從法國傳入日本的美味炸餅,名字取自法語中的「croquette」,這酥脆小食的日語發音「コロッケ」(korokke),與漢語「可樂」的發音相近而被稱「可樂餅」。今天河馬媽媽版的可樂餅,將馬鈴薯混合
  • 新作《運算消消消》登iOS 加加減減做消除
    新作《運算消消消》登iOS 加加減減做消除 來源:www.18183.com作者:糾結的烏龜時間:2014-11-14 分享到: 遊戲規則十分簡單,就是基本的加減乘除,玩家需要在特定的步數以內通過連接正確的數字和符號來達到目標數字
  • C語言|位運算(與運算,或運算,異或運算,取反,移位運算)
    與運算 &為按位與0的二進位補碼000000001的二進位補碼0000000115的二進位補碼00001111-1的二進位補碼111111112.或運算 |為按位或3. 異或運算 ^為按位異或,相同為0,不同為14. 取反 ~為按位取反5.
  • 老婆餅的做法
    其實咱們也有自己傳統的糕點,【老婆餅】就是其中一個十分知名的代表。老婆餅這個名字,總是讓人丈二和尚摸不著頭腦,從這個名字根本不知道是用什麼製作的,如果沒有吃過的朋友,甚至甜鹹口味都猜不到。其實老婆餅就是用麵粉、糯米粉、食用油等食材做的餅,不藉助任何添加劑和特殊的工具,就能達到香酥掉渣的效果。
  • 潮汕人會吃,四海皆知,這就來看潮派糕點,尤以老婆餅為先
    誰知道他們還特別善於取名——老婆餅這種「曠世奇名」,就出自潮州人之手。老婆餅裡沒有老婆,而是包裹著飴糖、芝麻等餡料,外皮烤製成誘人的金黃,一層層油酥薄如棉紙,酥鬆無比,一口下去碎屑便掉了滿地,蜜糖般的香甜瞬間包裹口腔。今天就來說說潮派糕點:潮汕人會吃,四海皆知,這就來看潮派糕點,尤以老婆餅為先。
  • 老婆餅沒有老婆、菠蘿包沒有菠蘿……在廣東吃個飯,我又被騙了!
    蹦砂形似金黃色蝴蝶,順德俗稱蝴蝶為「嘣砂」,因此得名。蹦砂很好吃,南乳香香的特別勾人,吃起來「嘎嘎」脆,鹹中帶甜的~via 廣州吃喝玩樂煲仔飯源自廣東廣州,是用砂鍋(瓦煲)煮出米飯再碼上肉菜。而在廣東,砂鍋被稱為煲仔,因此得名煲仔飯。
  • 和蘭溪小姐姐學地道英語(8)——老婆餅裡沒有老婆!
    暑假回國的時候,帶Bob去糕餅店,他對著老婆餅看了半天
  • 如何用英語表達「加減乘除」?看完這篇你就懂啦!
    」,這個時候需要用「It『s…」句型回答,也就是:「It’s three.比如你想說「12÷2=6」,在英語裡是這樣的「12 divided by 2 is 6.」除了需要使用到by以外,你注意到第二個細節了嗎?