原碼 反碼 補碼 概念 原理 詳解
參考:
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE));//[0]1111111111111111111111111111111,注意最前面的符號位0被省略了 System.out.println(Integer.toBinaryString(Integer.MIN_VALUE));//10000000000000000000000000000000,32位,注意這裡都是用補碼錶示的 System.out.println(Integer.toBinaryString(1));//1,注意前面所有的0都被省略了 System.out.println(Integer.toBinaryString(-1));//11111111111111111111111111111111,32位 System.out.println((Integer.MAX_VALUE + 1) == Integer.MIN_VALUE);//true,提示:Comparing identical相同的 expressions System.out.println((Integer.MIN_VALUE + (-1) == Integer.MAX_VALUE));//true
教科書式定義
軟考指定資料中關於原碼、反碼、補碼和移碼的定義如下(n是機器字長):雖然反人類,但是定義的的確很精確、精煉啊!
大話原碼、反碼、補碼、移碼
原碼
如果機器字長為n,那麼一個數的原碼就是用一個n位的二進位制數,其中最高位為符號位:正數為0,負數為1。剩下的n-1位表示該數的絕對值。例如:X=+101011 , [X]原= 0010_1011
X=-101011 , [X]原= 1010_1011
位數不夠的用0補全。PS:正數的原、反、補碼都一樣,0的原碼跟反碼都有兩個,因為這裡0被分為+0和-0。反碼
知道了原碼,那麼你只需要具備區分0跟1的能力就可以輕鬆求出反碼,為什麼呢?因為反碼就是在原碼的基礎上,符號位不變其他位按位取反(就是0變1,1變0)就可以了X=-101011 , [X]原= 1010_1011 ,[X]反=1101_0100
補碼
補碼也非常的簡單,就是在反碼的基礎上按照正常的加法運算加1。例如:X=-101011 , [X]原= 1010_1011 ,[X]反=1101_0100,[X]補=1101_0101
負數的補碼這麼記更簡單:符號位不變,其他的從低位開始,直到遇見第一個1之前,什麼都不變;遇見第一個1後保留這個1,以後按位取反。例:[-7]原= 1 000011_1
[-7]補= 1 111100_1
PS:0的補碼是唯一的,如果機器字長為8那麼[0]補=0000_0000。移碼
移碼最簡單了,不管正負數,只要將其補碼的符號位取反即可。例如:X=-101011 , [X]原= 1010_1011 ,[X]反=1101_0100,[X]補=1101_0101,[X]移=0101_0101
一些基本概念
本篇文章講解了計算機的原碼、反碼和補碼,並且進行了深入探求了為何要使用反碼和補碼,以及更進一步的論證了為何可以用反碼、補碼的加法計算原碼的減法。論證部分如有不對的地方請各位牛人幫忙指正!機器數和符號位
在學習原碼、反碼和補碼之前,需要先了解機器數和真值的概念。一個數在計算機中的二進位制表示形式, 叫做這個數的機器數。機器數是帶符號的,在計算機用一個數的最高位存放符號, 正數為0、負數為1。
比如,十進位制中的數 +3 ,如果計算機字長為8位,轉換成二進位制就是0000_0011。如果是 -3 ,就是 1000_0011(原碼) 。
那麼,這裡的 0000_0011 和 1000_0011(原碼) 就是機器數。
真值
因為第一位是符號位,所以機器數的形式值就不等於真正的數值。例如上面的有符號數 1000_0011,其最高位1代表負,其真正數值是 -3,而不是形式值131(10000011轉換成十進位制等於131)。所以,為區別起見,將帶符號位的機器數對應的真正數值稱為機器數的真值。例:0000_0001的真值 = +000_0001 = +1,1000_0001的真值 = –000_0001 = –1
在探求為何機器要使用補碼之前,讓我們先了解原碼、反碼和補碼的概念。對於一個數,計算機要使用一定的編碼方式進行儲存,原碼、反碼、補碼是機器儲存一個具體數字的編碼方式。
原碼
原碼就是符號位加上真值的絕對值,即用第一位表示符號,其餘位表示值。比如如果是8位二進位制:[+1]原 = 0000_0001
[-1]原 = 1000_0001
因為第一位是符號位,所以8位二進位制數的取值範圍就是:[1111_1111 , 0111_1111] 即 [-127 , 127] 注意不是[-128 , 127] 或[-128 , 128] 原碼是人腦最容易理解和計算的表示方式。
反碼
反碼的表示方法是:正數的反碼是其本身。負數的反碼是在其原碼的基礎上,【符號位不變】,其餘各個位【取反】。
[+1] = [0000_0001]原 = [0000_0001]反
[-1] = [1000_0001]原 = [1111_1110]反
可見如果一個反碼錶示的是負數,人腦無法直觀的看出來它的數值,通常要將其轉換成原碼再計算。補碼
補碼的表示方法是:正數的補碼就是其本身。負數的補碼是在其原碼的基礎上,【符號位不變】,其餘各位取反,最後+1,即【取反+1】。
[+1] = [0000_0001]原 = [0000_0001]反 = [0000_0001]補
[-1] = [1000_0001]原 = [1111_1110]反 = [1111_1111]補
對於負數,補碼錶示方式也是人腦無法直觀看出其數值的,通常也需要轉換成原碼再計算其數值。以上概念其實很好理解,就是一些規則而已,但問題是,為什麼要制定這些規則呢?下面我們就來探討探討這個問題。
為何要使用原碼、反碼和補碼
現在我們知道了,計算機可以有三種編碼方式表示一個數,對於正數因為三種編碼方式的結果都相同,所以不需要過多解釋。但是對於負數,其原碼、反碼和補碼是完全不同的。既然原碼才是被人腦直接識別並用於計算表示方式,為何還會有反碼和補碼呢?首先,希望能用符號位代替減法...
首先,因為人腦可以知道第一位是符號位,在計算的時候我們會根據符號位選擇對真值區域的加減。但是對於計算機,加減乘數是最最最最基礎的運算,要設計的儘量簡單,計算機辨別"符號位"會讓計算機的基礎電路設計變得複雜,於是,人們想出了將符號位也參與運算的方法。我們知道,根據運演算法則,減去一個正數等於加上一個負數,即:1-1 = 1 + (-1),所以機器可以只有加法而沒有減法,這樣計算機運算的設計就更簡單了。但是,用原碼計算時有一些問題...
於是人們就開始探索將符號位參與運算並且只保留加法的方法。首先來看原碼:1 - 1 = 1 + (-1) = [0000_0001]原 + [1000_0001]原 = [1000_0010]原 = -2
如果用原碼錶示, 讓符號位也參與計算,顯然對於減法來說結果是不正確的。這也就是為何計算機內部不使用原碼錶示一個數。PS:
對於上一句話,白哥要打一個大大的問號?雖說包括Java、C在內的很多程式語言,在設計整型時,其定義都是:
【8/16/32/64-bit signed two's complement integer】
即:
【8/16/32/64位有符號二進位制補碼整數】
但也不能說計算機內部不是採用原碼錶示的吧?
於是,反碼出現了,但還有問題...
為了解決原碼做減法的問題,出現了反碼:1 - 1 = 1 + (-1) = [0000_0001]原 + [1000_0001]原= [0000_0001]反 + [1111_1110]反 = [1111_1111]反
= [1000_0000]原 = -0
發現用反碼計算減法,結果的真值部分是正確的,而唯一的問題其實就出現在"0"這個特殊的數值上。雖然人們理解上+0和-0是一樣的,但是0帶符號是沒有任何意義的,而且會有[0000_0000]原和[1000_0000]原兩個編碼表示0。補碼解決了遺留的這個問題..
於是補碼出現了,它解決了0的符號以及兩個編碼的問題:1-1 = 1 + (-1) = [0000_0001]原 + [1000_0001]原 = [0000_0001]補 + [1111_1111]補 = [0000_0000]補
=[0000_0000]原 = 0
這樣0用[0000_0000]表示, 而以前出現問題的-0則不存在了。並且,還有意外收穫..
除此之外,還可以用 [1000_0000]補 表示-128:(-1) + (-127) = [1000_0001]原 + [1111_1111]原 = [1111_1111]補 + [1000_0001]補 = [1000_0000]補
-1-127的結果應該是-128,在用補碼運算的結果中, [1000_0000]補 就代表-128。注意,-128並沒有原碼和反碼錶示。使用補碼不僅僅修復了0的符號以及存在兩個編碼的問題,而且還能夠多表示一個最低數,這就是為什麼8位二進位制使用原碼或反碼錶示的範圍為 [-127, +127],而使用補碼錶示的範圍為 [-128, 127] 的原因。因為機器使用補碼,所以對於程式設計中常用到的32位int型別可以表示範圍是 [-2^31, 2^31-1] ,因為第一位表示的是符號位,而使用補碼錶示時又可以多儲存一個最小值。
從數學角度深究原碼、反碼、補碼
警告:以下因為涉及到數學原理性的問題,個人不保證絕對正確,且極有可能出現一些原理性錯誤,請謹慎對待!計算機巧妙地把符號位參與運算,並且將減法變成了加法,背後蘊含了怎樣的數學原理呢?
將鐘錶想象成是一個1位的12進位制數,如果當前時間是6點,我希望將時間設定成4點,需要怎麼做呢?我們可以:
1. 往回撥2個小時: 6 - 2 = 4
2. 往前撥10個小時: (6 + 10) mod 12 = 4
3. 往前撥10+12=22個小時: (6+22) mod 12 =4
2,3方法中的mod是指取模操作,16 mod 12 = 4 即用16除以12後的餘數是4。所以鐘錶往回撥(減法)的結果可以用往前撥(加法)替代!
現在的焦點就落在瞭如何用一個正數來替代一個負數。上面的例子我們能感覺出來一些端倪,發現一些規律。但是數學是嚴謹的,不能靠感覺。
首先介紹一個數學中相關的概念:同餘
同餘的概念
兩個整數a、b,若它們除以整數m所得的餘數相等,則稱a,b對於模m同餘記作 a ≡ b (mod m)
讀作 a 與 b 關於模 m 同餘。
舉例說明:
4 mod 12 = 4
16 mod 12 = 4
28 mod 12 = 4
所以4, 16, 28關於模 12 同餘。負數取模的計算
正數進行mod運算是很簡單的,但是負數呢?下面是關於mod運算的數學定義:
上面是截圖,下面是使用"["和"]"替換上圖的"取下界"符號:
x mod y = x - y [ x / y ]
上面公式的意思是:x mod y 等於 x 減去 y 乘上 x與y的商的下界
以 -3 mod 2 舉例:
-3 mod 2
= -3 - 2*[-3/2]
= -3 - 2*[-1.5]
= -3 - 2*(-2)
= -3 + 2
= 1
所以:(-2) mod 12 = 12-2 =10
(-4) mod 12 = 12-4 = 8
(-5) mod 12 = 12 - 5 = 7
數學證明
再回到時鐘的問題上:回撥2小時 = 前撥10小時
回撥4小時 = 前撥8小時
回撥5小時= 前撥7小時
注意這裡發現的規律!結合上面學到的同餘的概念,實際上:
(-2) mod 12 = 10
10 mod 12 = 10
-2與10是同餘的(-4) mod 12 = 8
8 mod 12 = 8
-4與8是同餘的距離成功越來越近了,要實現用正數替代負數,只需要運用同餘數的兩個定理:
反身性:
a ≡ a (mod m)
這個定理是很顯而易見的。線性運算定理:
如果a ≡ b (mod m),c ≡ d (mod m) 那麼:
(1)a ± c ≡ b ± d (mod m)
(2)a * c ≡ b * d (mod m)
所以:7 ≡ 7 (mod 12)
(-2) ≡ 10 (mod 12)
7 -2 ≡ 7 + 10 (mod 12)
現在我們為一個負數找到了它的正數同餘數,但是並不是 7-2 = 7+10,而是 7 -2 ≡ 7 + 10 (mod 12),即計算結果的餘數相等。接下來回到二進位制的問題上,看一下:2-1=1的問題。
2-1=2+(-1) = [0000 0010]原 + [1000 0001]原= [0000 0010]反 + [1111 1110]反
先到這一步,-1的反碼錶示是1111 1110,如果這裡將[1111 1110]認為是原碼,則[1111 1110]原 = -126,這裡將符號位除去,即認為是126。發現有如下規律:
(-1) mod 127 = 126
126 mod 127 = 126
即:(-1) ≡ 126 (mod 127)
2-1 ≡ 2+126 (mod 127)
2-1 與 2+126的餘數結果是相同的!而這個餘數,正式我們的期望的計算結果:2-1=1所以說一個數的反碼,實際上是這個數對於一個膜的同餘數;而這個膜並不是我們的二進位制,而是所能表示的最大值!這就和鐘錶一樣,轉了一圈後總能找到在可表示範圍內的一個正確的數值!
而2+126很顯然相當於鐘錶轉過了一輪,而因為符號位是參與計算的,正好和溢位的最高位形成正確的運算結果。
既然反碼可以將減法變成加法,那麼現在計算機使用的補碼呢?為什麼在反碼的基礎上加1還能得到正確的結果?
2-1=2+(-1) = [0000 0010]原 + [1000 0001]原 = [0000 0010]補 + [1111 1111]補
如果把[1111 1111]當成原碼,去除符號位,則:[0111 1111]原 = 127
其實,在反碼的基礎上+1,只是相當於增加了膜的值:(-1) mod 128 = 127
127 mod 128 = 127
2-1 ≡ 2+127 (mod 128)
此時,錶盤相當於每128個刻度轉一輪,所以用補碼錶示的運算結果最小值和最大值應該是[-128, 128]。但是由於0的特殊情況,沒有辦法表示128,所以補碼的取值範圍是[-128, 127]
相關推薦
原碼 反碼 補碼 概念 原理 詳解
轉自:https://www.cnblogs.com/baiqiantao/p/7442907.html參考:System.out.println(Integer.toBinaryString(Integer.MAX_VALUE));//[0]1111111111111111
原碼, 反碼, 補碼 詳解
替代 表達 技術分享 焦點 文章 相同 ima 等於 來看 本篇文章講解了計算機的原碼, 反碼和補碼. 並且進行了深入探求了為何要使用反碼和補碼, 以及更進一步的論證了為何可以用反碼, 補碼的加法計算原碼的減法. 論證部分如有不對的地方請各位牛人幫忙指正! 希望本文對大家
原碼反碼補碼詳解
而是 bsp 沒有 結果 如果 絕對值 來看 解讀 問題 原碼: 原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其余位表示值. 比如如果是8位二進制: [+1]原 = 0000 0001 [-1]原 = 1000 0001 第一位是符號位. 因為第一位是符號位,
【軟考】原碼, 反碼, 補碼 詳解
本篇文章講解了計算機的原碼, 反碼和補碼. 並且進行了深入探求了為何要使用反碼和補碼, 以及更進一步的論證了為何可以用反碼, 補碼的加法計算原碼的減法. 論證部分如有不對的地方請各位牛人幫忙指正! 希望本文對大家學習計算機基礎有所幫助! 一. 機器數和真值 在學習原碼, 反碼和補碼之前, 需要先了解
原碼反碼補碼推導原理
被加數 被減數 加數 減數———— ———— 和 差 減法和
看到一篇不錯的文章 轉載一下:原碼, 反碼, 補碼 詳解
本篇文章講解了計算機的原碼, 反碼和補碼. 並且進行了深入探求了為何要使用反碼和補碼, 以及更進一步的論證了為何可以用反碼, 補碼的加法計算原碼的減法. 論證部分如有不對的地方請各位牛人幫忙指正! 希望本文對大家學習計算機基礎有所幫助! 一. 機器數和真值 在學習原碼, 反碼和補碼之前, 需要先了解
轉載:原碼, 反碼, 補碼 詳解
原文搬過來,如下: 本篇文章講解了計算機的原碼, 反碼和補碼. 並且進行了深入探求了為何要使用反碼和補碼, 以及更進一步的論證了為何可以用反碼, 補碼的加法計算原碼的減法. 論證部分如有不對的地方請各位牛人幫忙指正! 希望本文對大家學習計算機基礎有所幫助!
原碼反碼補碼移碼轉換詳解
下面都以8位為例,說明問題即可。 一、原碼(-127—127): 原碼求法:有符號數的二進位制表示。 例如:4 = 0000 0100(
python之將byte轉換為int型別函式 int.from_bytes 詳解與原碼反碼補碼的簡單介紹
函式格式:int.from_bytes(bytes, byteorder, *, signed=False)簡單demo:s1 = b'\xf1\xff' print(int.from_bytes(s1, byteorder='big', signed=False)) pri
2進位制原碼反碼補碼,2進位制加減乘除原理
二進位制用補碼做加減法 1.最高位為符號位,0正1負;加減法都使用補碼形式的加法;正數補碼為原碼本身;負數補碼為其反碼+1;運算結果位數溢位的部分捨棄 8+2=10 000
計算機原理:二進位制 原碼 反碼 補碼
在計算機中,1byte=8位,若是無符號的情況下可表示的數字總個數為2^8=256個數,但是計算機只會進行加法運算例如: 5-4 =1 在計算機中的運算方式是 5+(-4)=1,故在計算機中要加入負數的概念,以方便加減法運算。 二進位制的字串中區分正負數,做了以
組成原理原碼反碼補碼移碼
一. 機器數和真值 在學習原碼, 反碼和補碼之前, 需要先了解機器數和真值的概念. 1、機器數 一個數在計算機中的二進位制表示形式, 叫做這個數的機器數。機器數是帶符號的,在計算機用一個數的最高位存放符號, 正數為0, 負數為1. 比如,十進位制中的數 +3 ,計算機
02.15_Java語言基礎(原碼反碼補碼的講解).avi
cnblogs logs 基礎 java語言基礎 alt blog 補碼 http nbsp 02.15_Java語言基礎(原碼反碼補碼的講解).avi
java基礎:原碼反碼補碼
gin 微軟雅黑 基礎 image p s 分享 ont style mil 計算機在操作的時候,都是采用數據對應二進制的補碼來計算的: 原碼 反碼 補碼 原碼:用原碼,反碼,補碼來分別表示+7,和-7. 首先得到7的二進制:111 java基
計算機基礎知識_原碼反碼補碼
註意 bsp 標題 都是 包含 找到 sde strong c/c++ 一、原碼,反碼,補碼 1.原碼 比如一個二進制數字 最高位是0,(0代表正數) 0010 1000 那麽原碼就是0010 1000 反碼: 0010 1000 補碼: 0010 1000 都是一樣的
原碼 反碼 補碼
div 就會 二進制 dash post 整數 pri printf 其余 概述:數值的表示方法——原碼、反碼和補碼原碼:最高位為符號位,其余各位為數值本身的絕對值 反碼正數:反碼與原碼相同負數:符號位為 1,其余位對原碼取反 補碼正數:原碼、反
20.原碼反碼補碼及圖形化界面
圖形化界面 mfc war 一位 num mem tin warn stdio.h 1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdlib.h> 3 #include <stdio.h&
原碼 反碼 補碼 練習
32位 log 輸出 lin .com ati 用兩個 整數 use #include "iostream" using namespace std; #define INT_MIN (-2147483647-1) int main() { int i = -I
二進制中的原碼反碼補碼
log 結果 範圍 點擊 -- 計算機 絕對值 無法 數值 二進制中的原碼、反碼、補碼 1. 原碼 原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其余位表示值. 比如如果是8位二進制: [+1]原 = 0000 0001 [-1]原 = 1000 0001 第
原碼反碼補碼
法規 二進制 兩種 符號 方法 限制 大小 硬件 問題 對於原碼反碼補碼的問題,對應的在計算機內,定點數有3種表示法:原碼、反碼和補碼 所謂原碼就是二進制定點表示法,即最高位為符號位,“0”表示正,“1”表示負,其余位表示數值的大小。 反碼表示法規定:正數的反碼與其原碼