我們現(xiàn)實(shí)生活中用的最多的就是十進(jìn)制,逢十進(jìn)一.
但是我們的計(jì)算機(jī)為什么要采用二進(jìn)制?
如果懂電路的朋友就很容易理解.用雙穩(wěn)態(tài)電路表示二進(jìn)制數(shù)字0和1是很容易的事情西壮。但是用上十進(jìn)制將會(huì)及其復(fù)雜.
當(dāng)然二進(jìn)制數(shù)0和1正好與邏輯量“真”和“假”相對(duì)應(yīng)股冗,因此用二進(jìn)制數(shù)表示二值邏輯顯得十分自然。
進(jìn)制之間可以互相轉(zhuǎn)換句惯,最常用的是 二進(jìn)制 八進(jìn)制 十進(jìn)制 十六進(jìn)制
十進(jìn)制 | 二進(jìn)制 | 八進(jìn)制 | 十六進(jìn)制 |
---|---|---|---|
100 | 1100100 | 144 | 64 |
1000 | 1111101000 | 1750 | 3e8 |
以上簡(jiǎn)單枚舉兩個(gè)數(shù)的轉(zhuǎn)換.下面來(lái)介紹下如何進(jìn)制轉(zhuǎn)換.
- 十進(jìn)制轉(zhuǎn)二進(jìn)制
方法為:十進(jìn)制數(shù)除2取余法莺禁,即十進(jìn)制數(shù)除2汪疮,余數(shù)為權(quán)位上的數(shù)返咱,得到的商值繼續(xù)除2,依此步驟繼續(xù)向下運(yùn)算直到商為0為止哥放。
下圖是 十進(jìn)制的100 轉(zhuǎn)為二進(jìn)制的演示:
從最后一個(gè)余數(shù)讀到第一個(gè)的,所以十進(jìn)制的100轉(zhuǎn)為二進(jìn)制就是: 1100100
- 二進(jìn)制轉(zhuǎn)為十進(jìn)制
把二進(jìn)制數(shù)按權(quán)展開(kāi)歼指、相加即得十進(jìn)制數(shù)。
我們繼續(xù)以 1100100 為例.
我們展開(kāi)后:
(1 * 2^7) + (1 * 2^6) + (0 * 2^5) + (0 * 2^4) + (1 * 2^3) + (0 * 2^2) + (0 * 2^1) = 100
- 二進(jìn)制轉(zhuǎn)換十六進(jìn)制
十六進(jìn)制取四合一甥雕,不足時(shí)補(bǔ)0
這次以 101111 為例.
我們可以把 1100100 分成兩個(gè)部分 0010 和 1111. 每四個(gè)為一組.一組最大是1111踩身,也就是十進(jìn)制的15.
十進(jìn)制 | 十六進(jìn)制 |
---|---|
10 | A |
11 | B |
12 | C |
13 | D |
14 | E |
15 | F |
所以結(jié)果就是2F.
這里就不過(guò)多介紹啦.這上面是我常用的方法.有興趣的可以去百度來(lái)了解更多方法.
計(jì)算機(jī)中所有數(shù)據(jù)都已二進(jìn)制保存,我們已經(jīng)知道0010 1111 對(duì)應(yīng)的是 十進(jìn)制的 15, 那么 -15 將如何在計(jì)算機(jī)中表示呢? 我們將引入 原碼,反碼,補(bǔ)碼 三個(gè)概念.
- 原碼
第一位用來(lái)表示符號(hào)位,其余表示值.正數(shù)的符號(hào)為0,負(fù)數(shù)的符號(hào)位為1
100 的二進(jìn)制原碼是:0110 0100
-100 的二進(jìn)制原碼是: 1110 0100
但原碼有個(gè)缺陷就是有兩個(gè)數(shù)可以表示0, 1000 0000 和 0000 0000
- 反碼
正數(shù)的反碼是本事,負(fù)數(shù)的反碼是符號(hào)位保持不變,其余位取反.
100 的二進(jìn)制反碼是:0110 0100
-100 的二進(jìn)制反碼是: 1001 1011
- 補(bǔ)碼
正數(shù)的補(bǔ)碼是其本身社露,負(fù)數(shù)的補(bǔ)碼是在其反碼的基礎(chǔ)上+1
100 的二進(jìn)制補(bǔ)碼是:0110 0100
-100 的二進(jìn)制補(bǔ)碼是: 1001 1100
計(jì)算機(jī)選擇補(bǔ)碼作為數(shù)字的存儲(chǔ)方式,是有原因的.
使用補(bǔ)碼表示負(fù)整數(shù)挟阻,那么ALU在做整數(shù)之間的操作時(shí),就不用區(qū)分符號(hào)了,所有位都會(huì)參與運(yùn)算附鸽。
這部分比較難理解.只要了解這三個(gè)概念即可.隨著深入學(xué)習(xí)會(huì)慢慢理解為什么采用補(bǔ)碼.
同樣我們也知道了一個(gè)問(wèn)題就是int類型的取值范圍為什么是-2147483648 — 2147483647
int 類型有四個(gè)字節(jié), 一個(gè)字節(jié)有8位.總長(zhǎng)度32位.
按照補(bǔ)碼方式存儲(chǔ)最大值是 0111 1111 1111 1111 1111 1111 1111 1111
最小為 1000 0000 0000 0000 0000 0000 0000 0001
通過(guò)更深入的學(xué)習(xí),我們可以知道計(jì)算機(jī)是通過(guò)CPU執(zhí)行命令.但是沒(méi)有提供直接加減法操作的邏輯.我們只可以通過(guò)位運(yùn)算來(lái)實(shí)現(xiàn).
什么是位運(yùn)算呢?
位運(yùn)算符 | 說(shuō)明 | 舉例 |
---|---|---|
按位與(&) | 相應(yīng)位上的數(shù)都是1時(shí),該位才取1,否則該為為0 | 1 & 0 = 0, 1 & 1 = 1 |
按位或(|) | 只要相應(yīng)位上存在1,那么該位就取1,均不為1,即為0 | 1 & 0 = 1, 0 & 0 = 0 |
按位異或(^) | 只有當(dāng)相應(yīng)位上的數(shù)字不相同時(shí),該為才取1,若相同,即為0 | 1 ^ 0 = 1, 1 ^ 1 = 0 |
取反(~) | 取反運(yùn)算,每個(gè)位上都取相反值,1變成0,0變成1 | ~0 = 1 , ~1 =0 |
左移(<<) | 將一個(gè)數(shù)各二進(jìn)制位全部向左移動(dòng)若干位 | 2 (0010) << 2 = 8(1000) |
右移(>>) | 將一個(gè)數(shù)各二進(jìn)制位全部向右移動(dòng)若干位 | 12(1100) >> 2 = 3(0011) |
那如何實(shí)現(xiàn)我們的加法操作呢?
以 1 + 2為例
1 .... (0001)
2 .... (0010)
-------------
0011
這有點(diǎn)像我們上面的 按位異或 運(yùn)算.我們?cè)僭囈粋€(gè) 3 + 5
3 .... (0011)
5 .... (0101)
-------------
1000
這次的運(yùn)算我們需要進(jìn)位,不用進(jìn)位那結(jié)果就是 0110 和按位異或運(yùn)算結(jié)果一樣.那我們?nèi)绾闻袛嗍欠裥枰M(jìn)位呢. 只有當(dāng)對(duì)應(yīng)數(shù)為 1 的時(shí)候才考慮進(jìn)位.可以使用按位與運(yùn)算符來(lái)判斷.直到按位與的結(jié)果為0時(shí),就不需要進(jìn)位了.
我們重新理一遍步驟.
- 0011 與 0101 進(jìn)行按位異或運(yùn)算得出結(jié)果 0110
- 0011 與 0101 進(jìn)行按位與運(yùn)算判斷是否需要位移 0001,結(jié)果不為0需要位移,位移后結(jié)果為0010
- 0110 與 0010 進(jìn)行按位異或運(yùn)算得出結(jié)果 0100
- 0110 與 0010 進(jìn)行按位與運(yùn)算判斷是否需要位移 0010,結(jié)果不為0需要位移,位移后結(jié)果為0100
- 0100 與 0100 進(jìn)行按位異或運(yùn)算得出結(jié)果 0000
- 0100 與 0100 進(jìn)行按位與運(yùn)算判斷是否需要位移 0100,結(jié)果不為0需要位移,位移后結(jié)果為1000
- 0000 與 0100 進(jìn)行按位異或運(yùn)算得出結(jié)果 0100
- 0000 與 0100 進(jìn)行按位與運(yùn)算判斷是否需要位移 0000,結(jié)果為0不需要再位移.所以結(jié)果就是 0100
總結(jié):異或?qū)崿F(xiàn)兩數(shù)相加不進(jìn)位,按位與實(shí)現(xiàn)進(jìn)位
下面貼出一個(gè)C寫(xiě)的代碼
#include <stdio.h>
int bitAdd(int a, int b)
{
int sum, carry;
if (b == 0){return a;} // 當(dāng)按位與的結(jié)果為0 則表示已無(wú)需進(jìn)位
sum = a ^ b;
carry = (a & b) << 1;
return bitAdd(sum, carry);
}
int main()
{
printf("運(yùn)算結(jié)果: %d", bitAdd(3, 5));
return 0;
}
減法的實(shí)現(xiàn)再底層也是加法. 5 - 3 就相當(dāng)于 5 + (-3). 同理乘除也是一樣.
這篇的最后一個(gè)知識(shí)點(diǎn)—字節(jié)序.
計(jì)算機(jī)硬件有兩種儲(chǔ)存數(shù)據(jù)的方式: 大端字節(jié)序(big endian)和小端字節(jié)序(little endian)
比如1000 用大端字節(jié)序表示就是 0×03E8脱拼。
我們習(xí)慣讀寫(xiě)大端字節(jié)序。所以坷备,除了計(jì)算機(jī)的內(nèi)部處理熄浓,其他的場(chǎng)合幾乎都是大端字節(jié)序,比如網(wǎng)絡(luò)傳輸和文件儲(chǔ)存省撑。不同處理器的存儲(chǔ)方式也是不同的.
我們寫(xiě)個(gè)Demo看看本機(jī)是如何存儲(chǔ)的.筆者使用的是Win10
#include <stdio.h>
int main()
{
int a = 1000;
printf("存放地址: %p", &a);
return 0;
}
通過(guò)Visual Studio提供的調(diào)試工具我們查看內(nèi)存.
內(nèi)存中存儲(chǔ)的是 e803 . 這就是小端存儲(chǔ).
#include <stdio.h>
int main()
{
int a = 0*1234;
char* p;
p = (char*)& a;
if (p == 0*12)
{
printf("大端存儲(chǔ)");
}
else
{
printf("小端存儲(chǔ)");
}
return 0;
}
利用這種方法可以判斷本機(jī)的存儲(chǔ)方式.
好啦赌蔑。今天的分享就到這啦.