C语言取字节的第n二进制,学C语言的看过来,最完整进制转换、整数和小数内存存储模型...
什么是進制
進制也就是進位計數制,是人為定義的帶進位的計數方法。對于任何一種進制---N進制,就表示每一位置上的數運算時都是逢N進一位。
數數相信大家都會了,比如0 1 2 3 4 5 6 7 8 9 10 11 12 13...,在數數時某一位數量滿10了就向前進位,這種逢十進一的進位制,就叫十進制。
不過在日常生活中,并不止這一種進位制,比如1小時有60分鐘,1分鐘有60秒,滿60進一,這就是六十進制。
而在計算機中常用的進制除了十進制,還有二進制、八進制、十六進制
二進制
組成:0 1
規則:逢二進一
表示方式:二進制數1000010可寫成(1000010)2或寫成1000010B
八進制
組成:0 1 2 3 4 5 6 7
規則:逢八進一
表示方式:八進制數520可寫成(520)8或寫成520O
十六進制
組成:0 1 2 3 4 5 6 7 8 9 A B C D E F
規則:逢十六進一
表示方式:十六進制的520可以寫成(520)16或寫成520H
為什么在計算機中,有這么多種進制表示方式?
方便:二進制數中只有兩個數碼0和1,可用具有兩個不同穩定狀態的元器件來表示一位數碼。
簡單:二進制數運算簡單,大大簡化了計算中運算部件的結構,0+0=0,0+1=1,1+0=1,1+1=10。
真假:二進制天然兼容邏輯運算。
缺點:二進制計數在日常使用上有個不便之處,就是位數往往很長,讀寫不便,如:把十進制的100000D寫成二進制就是11000011010100000B,所以計算機領域我們實際采用的是十六進制。二進制數轉換為十六進制數時,長度縮減為原先的約四分之一,把十進制的100000寫成八進制就是303240。十六進制的一個數位可代表二進制的四個數位。這樣,十進制的100000寫成十六進制就是186A0。
存儲單位
我們平常使用的程序,如:Windows操作系統、打字軟件、游戲軟件等。一般安裝在硬盤等外存上,但僅此是不能使用其功能,必須把它們調入內存中運行,才能真正使用其功能。
因為內存的讀寫速度相對于外存來說非常快,但是內存是暫時存儲程序以及數據的地方。當我們使用WPS處理文稿時,當你在鍵盤上敲入字符時,它被存入內存中。當你選擇存盤時,內存中的數據才會被存入硬(磁)盤。
內存是由無數個晶體管組成的(可以理解為燈泡),一個晶體管作為一比特(bit)的存儲器。每個晶體管可以存儲一個二進制0或1,比特通常也叫做位。
位(bit): 計算機存儲的最小單位
字節(byte): 數據表示的最小單位
一個字節通常8位長 1byte = 8 bit
千字節(KB):
1KB = 1024byte
為什么是1024,而不是1000呢?二的十次方剛好是1024,就這么表示啦~
字節以上的轉換單位都是1024,只有一個字節等于八個位是不一樣的...
思考:為什么硬盤標注的容量與實際的容量不一樣?
買的256G硬盤實際上只有238.4G,咱們一起來換算一下:
硬盤廠商十進制計算:256G = 256,000MB = 256,000,000KB = 256,000,000,000Byte 以1000為單位換算操作系統二進制計算: 256G = 262,144MB = 268,435,456KB = 274,877,906,944Byte 以1024為單位換算那么256G實際容量:256,000,000,
000Byte/1024MB/1024MB/1024MB = 238.4G
所以,買256G硬盤實際上只有238.4G,而且容量越大差距也就越大了。
進制轉換
十進制轉其他進制:短除法
以十進制數520為例,分別轉換為二進制、八進制和十六進制,轉換過程如下:
其他進制轉十進制:位權相加
就以上面的520D的二進制、八進制和十六進制為例
首先,需要對其他進制從右往左依次開始編號,0 1 2 3 4 5 ...
然后,把每一位的數通過這個公式【數值 * 基數^編號】計算,然后把結果相加,即得到轉換結果
二進制10 0000 1000 轉十進制
98?7654?3210?編號
10?0000?1000?B
1*2^9?+?0?+?1*2^3?=?512?+?0?+?8?=?520?D
八進制1010 轉十進制
3210?編號
1010?O
1*8^3?+?0?+1*8^0??=?520?+?8?=520?D
十六進制208 轉十進制
210?編號
208?H
2*16^2?+?0?+?8*16^0?=?2*256?+?8?=?520?H
八進制、十六進制與二進制相互轉換:拆位
八進制與二進制
一個八進制數可以拆分為3個二進制數,3個二進制數可以合成一個八進制數
//二進制轉八進制
001?000?001?000?B
1???0???1???0???O
//八進制轉二進制
1???3???1???4???5???2???0????O
001?011?001?100?101?010?000??B
十六進制與二進制
一個八進制數可以拆分為4個二進制數,4個二進制數可以合成一個八進制數
//二進制轉十六進制
0010?0000?1000?B
2????0????8????H
//十六進制轉二進制
1????3????1????4????5????2????0????H
0001?0011?0001?0100?0101?0010?0000?B
為什么可以這樣拆位呢?
三位二進制數表示的范圍是[0 - 8) -> 2^3 對于八進制來說剛剛好
四位二進制數表示的范圍是[0 - 16) -> 2^4 對于十六進制來說剛剛好
整數的存儲方式
一,機器數和機器數的真值
1,機器數
一個數在計算機中的二進制表示形式,叫做這個數的機器數。機器數是帶符號的,在計算機用機器數的最高位存放符號,正數為0,負數為1。
比如,十進制中的數 +3 ,計算機字長為8位,轉換成二進制就是0000 0011,如果是 -3 ,就是 100 00011 。
那么,這里的 0000 0011 和 1000 0011 就是機器數。
2,機器數的真值
因為第一位是符號位,所以機器數的形式值就不等于真正的數值。
例如上面的有符號數 1000 0011,其最高位1代表負,其真正數值是 -3,而不是形式值131(1000 0011轉換成十進制等于131)。所以,為區別起見,將帶符號位的機器數對應的真正數值稱為機器數的真值。
例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1
二,原碼, 反碼, 補碼
讓我們先了解原碼、反碼和補碼的概念。對于一個數,計算機要使用一定的編碼方式進行存儲,原碼、反碼、補碼是機器存儲一個具體數字的編碼方式。
1,原碼
原碼就是機器數,即用第一位表示符號,其余位表示值。比如:如果是8位二進制:
[+1]原= 0000 0001
[-1]原= 1000 0001
第一位是符號位,因為第一位是符號位,所以8位二進制數的取值范圍就是:(即第一位不表示值,只表示正負。)
[1111 1111 , 0111 1111] 即 [-127 , 127]
原碼是人腦最容易理解和計算的表示方式。
2,反碼
正數的反碼是其本身;
負數的反碼是在其原碼的基礎上,符號位不變,其余各個位取反。
[+1] = [0000 0001]原 = [0000 0001]反
[-1] = [1000 0001]原 = [1111 1110]反
可見如果一個反碼表示的是負數,人腦無法直觀地看出來它的數值。通常要將其轉換成原碼再計算。
3,補碼
正數的補碼就是其本身;
負數的補碼是在其原碼的基礎上,符號位不變,其余各位取反,最后+1。(也即在反碼的基礎上+1)
[+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]補
[-1] = [1000 0001]原 = [1111 1110]反 = [1111 1111]補
對于負數,補碼表示方式也是人腦無法直觀看出其數值的。通常也需要轉換成原碼再計算其數值。
三,為何要使用原碼、反碼和補碼
人腦可以知道第一位是符號位,在計算的時候我們會根據符號位,選擇對真值區域的加減。(真值的概念在本文最開頭) 但是對于計算機,加減乘數已經是最基礎的運算,要設計得盡量簡單,計算機辨別"符號位"顯然會讓計算機的基礎電路設計變得十分復雜!
于是人們想出了將符號位也參與運算的方法。我們知道,根據運算法則減去一個正數等于加上一個負數,即:1-1 = 1 + (-1) = 0, 所以機器可以只有加法而沒有減法,這樣計算機運算的設計就更簡單了。
我們以計算十進制表達式:1 - 1 = 0為例
首先來看原碼:
1 - 1 = 1 + (-1) = [0000 0001]原+ [1000 0001]原= [1000 0010]原= -2
如果用原碼表示,讓符號位也參與計算,顯然對于減法來說,結果是不正確的。這也就是為何計算機內部不使用原碼表示一個數。
為了解決原碼做減法的問題, 出現了反碼:
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的符號問題以及0的兩個編碼問題:
1-1 = 1 + (-1) = [0000 0001]原+ [1000 0001]原= [0000 0001]補+ [1111 1111]補= [1 0000 0000]補=[0000 0000]補=[0000 0000]原注意:進位1不在計算機字長里。
這樣0用[0000 0000]表示,而以前出現問題的-0則不存在了。而且可以用[1000 0000]表示-128:-128的由來如下:
(-1) + (-127) = [1000 0001]原+ [1111 1111]原= [1111 1111]補+ [1000 0001]補= [1000 0000]補
-1-127的結果應該是-128,在用補碼運算的結果中,[1000 0000]補就是-128,但是注意因為實際上是使用以前的-0的補碼來表示-128,所以-128并沒有原碼和反碼表示。(對-128的補碼表示[1000 0000]補,算出來的原碼是[0000 0000]元,這是不正確的)
使用補碼,不僅僅修復了0的符號以及存在兩個編碼的問題,而且還能夠多表示一個最低數。這就是為什么8位二進制,使用原碼或反碼表示的范圍為[-127, +127],而使用補碼表示的范圍為[-128, 127]。
整數的存儲是將十進制為的整數轉換成其相應的補碼后存儲。
小數的存儲方式
現如今的計算機中浮點數的存儲都是遵循IEEE754/854標準,以二進制的科學計數法存放到內存中。
對于浮點數在計算機中有兩種存儲的精度,即單精度和雙精度,單精度是32位,雙精度是64位。
符號S:0為正,1為負
尾數M:小數點后面的部分
指數E:即階碼,指明了小數點在數據中的位置
為了讓指數表示正、負引入了偏差碼,float的為127,double的為1024
十進制小數轉二進制小數
先把整數部分轉化為二進制
再把小數部分轉化為二進制(用2乘以小數部分,每次將結果整數取出,然后用剩余小數部分繼續乘以2,直到小數部分為零,或者達到要求的精度為止)
以float f = 5.25為例
整數部分:5 -> 101
小數部分:0.25 -> 0.01
0.25?*?2?=?0.5---?0
0.5??*?2?=?1.0??---?1
從上往下取值:0.01
最后結果:101.01 = 1.0101 * 2^2
可見指數實際值為2,加上偏差碼127,2 + 127 = 129,129的二進制為10000001B,因此不難得到,8.25在內存中的存儲情況為:
如果把這個值作為整型使用,將是一個很大的數字,是1084751872
把這個內存里面的值轉為十進制小數就很簡單了:
//1,首先判斷S表示的正負?????+
//2,計算出E實際表示的指數???1000?0001?=?129???129?-?127?=?2
//3,根據M寫出二進制小數形式?1.0101?*?2^2?=?101.01
//4,對二進制小數以小數點為界限開始編號
210?-1-2?編號
101.?0?1?B
1*2^2?+?0?+?1*2^0?+?0*2^(-1)?+?1*2^(-2)?=?4?+?1?+??0.25?=5.25
注意:
在二進制,第一個有效數字必定是“1”,因此這個“1”并不會存儲。
浮點數不能精確表示其范圍內的所有數。
可精確表示的數不是均勻分布的,越靠近0越稠密。
總結
以上是生活随笔為你收集整理的C语言取字节的第n二进制,学C语言的看过来,最完整进制转换、整数和小数内存存储模型...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 字符串基本操作 c语言,数据结构C语言字
- 下一篇: c语言 switch语句大小,C语言sw