跳到主要內容

[Concept] 二補數(2's Complement)除法跟模數的意義

計算機領域,負數常用二補數表示。
很多計算機書籍有介紹二補數,不再贅述。

這裡討論的是:把一個二補數,除以一個數 K,或對 K 取 Mod,得到的答案意義為何?
首先,二補數可視為 2^N ( 2 的 N 次方)減一純量,N 視為無窮大。
例如:-3
二補數表示法為:2^N - 3
二進位表示:(100000000...) - (11)

將 2^N 除以 K 取商,餘數丟棄,K 是 2 的冪次方(2, 4, 8, 16...),此商在數線上意義為何?

把 2^N 看成無窮多個班級所組成的人數,每班 K 人。由於 K 是 2 的冪次方,所以 2^N 人剛好能排滿 n 個班級,n 剛好也是 2 的冪次方:

 K K K K  ...  K  K
  
做以下觀察:
  • 任意正數 P ,(2^N - P) 是 -P 的二補數表示法。
  • (2^N - P) / K = n - Q = 2^某次方 - Q,是 Q 的二補數。
  • Q = ceiling(P/K),也就是假如 P/K = 3.45,那麼 Q 就是 3.45 進位 = 4。
  • 所以 2^某次方 - Q 就是 - ceiling(P/K) 的二補數表示。
  • (2^N - P) % K,也就是取模數,為 K - (P%K) = 1。
結論:
  1. 二補數除以 K,K 為 2 的冪次方,商還是二補數。
  2. 二補數 Mod K,即取模數,K 為 2 的冪次方,得到的結果,是一個純量,這個純量不是二補數。
  3. 二補數除以 K,K 為 2 的冪次方,跟正數除以 K 的意義有一樣的地方,算出的商為一個編號,代表第幾個班級,班級的編號從 0 開始。

    例如:P = 第 0, 1, 2, ... , K-1 個同學,被編在編號為 P/K = 0 的班級,P = 第 K+0, K+1, K+2, ... , 2K-1 被編在編號為 P/K = 1 的班級。

    同理,P = -1, -2, -3, ... , -K 的同學,屬於編號為二補數 (-P)/K = -1 的班級,-K-1, -K-2, -K-3, ... , -2K 屬於在編號為 -2 的班級。

  4. 二補數 (-P) % K,跟正數 P % K 行為意義有一樣的地方。

    假設 K = 8 ,即每 8 個人一班,每班學號從 0 開始到 7,假設 P 等於 15, P/K = 1,P % K = 15 % 8 = 7,代表第 15 人(0-based index)屬於編號為 1 的班級,且學號為 7 的同學。

    同理,二補數 (-15)/K = -2,二補數 (-15)%K = 1,所以由 0 開始倒著數,第 -15 個同學屬於編號為 -2 的班級,學號為 1 。
也許很難理解吧,但熟悉一下就會發現其中的奧秘,二補數除法,有時候可以增加運算的效率。




留言

這個網誌中的熱門文章

[Linux] Elementary OS 字體調校

用 gesetting 取得 elementary os 的等寬字體(這也是終端機默認字體): gsettings get org.gnome.desktop.interface monospace-font-name 會顯示目前字型跟字體大小: Roboto Mono 10 設定字體大小: gsettings set org.gnome.desktop.interface monospace-font-name 'Roboto Mono 12' 可以微調 text-scaling-factor: gsettings set org.gnome.desktop.interface text-scaling-factor <value>

[C++] 計算程式執行時間:clock 和 time 函式

要計算一段程式碼執行時間,可以用 time 函式: 1 2 3 4 5 time_t start, end; start = time(NULL); // DO SOMETHING... end = time(NULL); cout " [Msg] total time: " difftime(end, start) " sec" endl; time 函式的精確度只到達秒,如果要精確到毫秒等級,要用 clock 函式: 1 2 3 4 5 6 clock_t start, end; start = clock(); // DO SOMETHING... end = clock(); cout ( double )(finish - start) / CLOCKS_PER_SEC endl;

[Vim] 我的 .vimrc

我用過的文字編輯器有 sublime text/atom/notepad++/gedit 等等。 後來我在 window 和 Linux 寫程式還是比較慣用 vim。 以下整理我常用的 .vimrc:  set nu "show line number. set rnu "related line number. nmap ; : "replace ';' with ':' in normal mode. set ai "auto indent set mouse=a "activate mouse set expandtab "replace tab with space. set tabstop=4 "replace tab with 4 spaces. set bg=dark "background set to dark. color desert "color scheme. syntax on "enable syntax highlight. " auto complete: inoremap ( ()<Esc>i inoremap ' ''<Esc>i inoremap " ""<Esc>i inoremap [ []<Esc>i inoremap { {}<Esc>i set cursorline " active cursorline 到此 vim 搭配 Ctrl + N 當自動補全,已經很好用了,之後有好用設定會再補上來。