二進(jìn)制
十進(jìn)制小數(shù)轉(zhuǎn)二進(jìn)制小數(shù)
如 十進(jìn)制 0.75
0.75 * 2 = 1.5 ... 取整 1
0.5 * 2 = 1.0 ... 取整 1
所以得出二進(jìn)制小數(shù) 0.11
二進(jìn)制小數(shù)轉(zhuǎn)十進(jìn)制小數(shù)
如 二進(jìn)制 0.11
1 * 0.5(2的-1次方) = 0.5
1 * 0.25(2的-2次方)= 0.25
所以相加得出十進(jìn)制小數(shù) 0.75
說明:小數(shù)點后第一位是-1次方,下一位是-2次方惰蜜,依次類推
補(bǔ)數(shù)
補(bǔ)數(shù)可以簡單對應(yīng)到十進(jìn)制中的相反數(shù)蜘醋,如 10與-10互為相反數(shù)运授;
而在二進(jìn)制中就是用正數(shù)來表示的負(fù)數(shù)蝴韭,可能這話不太好理解
在二進(jìn)制表示負(fù)數(shù)值時够颠,一般會把最高位作為符號來使用,0:表示正數(shù)榄鉴,1:表示負(fù)數(shù)
看個例子
十進(jìn)制數(shù)1 對應(yīng)的二進(jìn)制數(shù)是 00000001
十進(jìn)制數(shù)-1 對應(yīng)的二進(jìn)制數(shù)是 履磨?
再算十進(jìn)制數(shù)1的相反數(shù)-1,在二進(jìn)制數(shù)中表示庆尘,其實就是算 00000001 的補(bǔ)數(shù)
補(bǔ)數(shù)的公式 :每一位數(shù)取反 蹬耘,然后再 + 1,加1的時候需要考慮進(jìn)位問題减余,等同于十進(jìn)制中滿10進(jìn)的1原則
00000001 取反 11111110 ,加1 惩系,得出補(bǔ)數(shù) 11111111
我們可以反向驗證下
00000001 + 11111111 = 0
00000001
+ 11111111 (這里該進(jìn)位的要進(jìn)位)
——————————
00000000
在計算機(jī)中減法的實現(xiàn)其實就是通過補(bǔ)數(shù)的方式實現(xiàn)的位岔,
比如1-1 = 0 => 1 + (-1) = 0 ,計算時全部轉(zhuǎn)成二進(jìn)制計算
移位運(yùn)算
左移
正數(shù)的移位基本和十進(jìn)制是一樣的如筛,左移一位是1x10,計算機(jī)就是1x2,所以左移就是2的n次方;
左移低位都是補(bǔ)0抒抬;
負(fù)數(shù)的左移杨刨,如 -14 << 2 = -56
在計算機(jī)遇到負(fù)數(shù),都是采用補(bǔ)數(shù)的方式-14的相反數(shù)是14
二進(jìn)制14 00001110
二進(jìn)制14的補(bǔ)數(shù)-14 11110001 +1 => 11110010
二進(jìn)制-14左移兩位 11001000
二進(jìn)制-14的補(bǔ)數(shù) 00110111 +1 => 00111000
十進(jìn)制得 -(32+16+8) =-56
右移
正數(shù)十進(jìn)制右移一位是1x0.1,計算機(jī)就是1x0.5(2的-1次方),所以右移就是2的n次方分之一;
右移正數(shù)高位都是補(bǔ)0擦剑;
當(dāng)負(fù)數(shù)時妖胀,若該數(shù)值是用補(bǔ)數(shù)表示的負(fù)數(shù)值,則右移后的所有高位補(bǔ)1
負(fù)數(shù)的右移惠勒,如 -14 >> 2 = -4
二進(jìn)制14 00001110
二進(jìn)制14的補(bǔ)數(shù)-14 11110001 +1 => 11110010
二進(jìn)制-14右移兩位 11111100
二進(jìn)制-14的補(bǔ)數(shù) 00000011 +1 => 00000100
十進(jìn)制得 -(4)
浮點數(shù)
計算機(jī)中浮點數(shù)表示法
在計算機(jī)中表示小數(shù)是采用浮點數(shù)表示法赚抡,所以像1011.0011這樣的小數(shù)形式,完全都是在紙上運(yùn)算的結(jié)果纠屋。
浮點數(shù)是指用符號涂臣、尾數(shù)、基數(shù)和指數(shù)這四部分來表示的小數(shù).其規(guī)定小數(shù)點前面的值固定為1的正則表達(dá)式.
IEEE規(guī)定的浮點數(shù)
(+-)m*n^e
+-:符號售担、
m :尾數(shù)赁遗、
n :基數(shù)、
e :指數(shù)族铆、
十進(jìn)制數(shù)0.5岩四,用浮點數(shù)表示
0.5 * 10^0
二進(jìn)制數(shù)0.11,用浮點數(shù)表示
1.1*2^-1
尾數(shù)部分:用的是將小數(shù)點前面的值固定為1的正則表達(dá)式哥攘;
指數(shù)部分:用的是EXCESS系統(tǒng)表現(xiàn)法剖煌,是指根據(jù)指數(shù)部分的最大值的一半,得出中間值献丑,記作0末捣,使得負(fù)數(shù)不需要用符號來表示(不知道為什么這樣設(shè)計);
比如指數(shù)部分8位 创橄,011111110 -> 126
用 EXCESS系統(tǒng)表現(xiàn)就是 126 - 127 = -1 ,因為255的一半127 是0
計算機(jī)中計算小數(shù)的時候其實都是按照下面存儲計算的箩做,并非采用IEEE規(guī)定的浮點數(shù)表示法,所以我認(rèn)為EXCESS系統(tǒng)表現(xiàn)方式就是為了方便與浮點數(shù)表示法做互相轉(zhuǎn)化的.
程序中常用的浮點數(shù)double與float內(nèi)部構(gòu)造(IEEE-754規(guī)定)
雙精度浮點數(shù)(64位):
1位 11位 52位
<--------><----------><--------------------->
符號部分 指數(shù)部分 尾數(shù)部分
單精度浮點數(shù)(32位):
1位 8位 23位
<--------><----------><--------------------->
符號部分 指數(shù)部分 尾數(shù)部分
從IEEE的規(guī)定的構(gòu)造中得出妥畏,
雙精度的有效尾數(shù)是52位邦邦,另加1位(該位即小數(shù)點前的1,但是實際內(nèi)存中不會存儲醉蚁,這是約定)燃辖,即53位,2^53网棍,對應(yīng)到十進(jìn)制的 10^15 ~ 10^16黔龟,所以在十進(jìn)制中有效位是15位
而單精度的有效尾數(shù)是23位,另加1位,即24位氏身,224,對應(yīng)到十進(jìn)制的107 ~ 10^8巍棱,所以十進(jìn)制中有效位是7位
摘自書里,直接看這個可能會清晰點
float a=0.75的二進(jìn)制
0-01111110-10000000000000000000000
其中蛋欣,
符號位0航徙,表示是正數(shù);1陷虎,表示負(fù)數(shù)
指數(shù)部分01111110到踏,轉(zhuǎn)化為十進(jìn)制是126,EXCESS系統(tǒng)表現(xiàn)為126-127=-1尚猿;
尾數(shù)部分10000000000000000000000窝稿,表示二進(jìn)制數(shù)1.10000000000000000000000(尾數(shù)部分表示的是了1.以后的部分);
所以谊路,
用二進(jìn)制數(shù)表示為1.1x2^-1,用十進(jìn)制表示位1.5x2^-1 = 0.75;
程序計算小數(shù)出錯的原因
綜上所述讹躯,計算機(jī)是無法處理無限循環(huán)的小數(shù),因此缠劝,在遇到循環(huán)小數(shù)時潮梯,計算機(jī)就會根據(jù)變量數(shù)據(jù)類型所對應(yīng)的長度將數(shù)值從中間截斷或四舍五入。比如說float 類型的0.1惨恭,在轉(zhuǎn)成二進(jìn)制數(shù)時就是無限循環(huán)的秉馏,所以計算機(jī)會根據(jù)float的尾數(shù)部分在23位處截取,舍棄后面的部分脱羡。
這里再舉一個例子
再按上面所說的萝究,再計算下 float a = 6.7 在計算機(jī)內(nèi)存中是如何存儲的
1、6 對應(yīng)的二進(jìn)制是00000110
0.7對應(yīng)的二進(jìn)制是10110011001100110011001...
0.7 * 2 =1.4 1
0.4 * 2 =0.8 0
0.8 * 2 =1.6 1
0.6 * 2 =1.2 1
0.2 * 2 =0.4 0
0.4 * 2 =0.8 0
0.8 * 2 =1.6 1
0.6 * 2 =1.2 1
后面就一直循環(huán)...
所以6.7的二進(jìn)制就是110.10110011001100110011001(保留有效位)锉罐,
2帆竹、這樣的數(shù)只是我們書面的表達(dá)方式,所以需要進(jìn)一步轉(zhuǎn)化脓规,需要先左移兩位栽连,將小數(shù)點移到有效數(shù)之后(或者說是第一個1之后),得出(1.1010110011001100110011001 * 2的2次方)
3侨舆、接著就是把得出得數(shù)單精度的浮點數(shù)表示法
符號部分:0
尾數(shù)部分:1010110011001100110011(23位)
指數(shù)部分:左移兩位秒紧,2 + 127 = 129 =>10000001
所以最后內(nèi)存存儲的結(jié)果是 0 - 10000001 - 1010110011001100110011
如何防止精度丟失
回避策略
即10公里差1厘米,這樣的誤差可以忽略不計
把小數(shù)轉(zhuǎn)換成正數(shù)來計算
就是把小數(shù)x10挨下、x100先擴(kuò)大計算熔恢,再縮小臭笆;
可以簡單看看Java中BigDecimal的實現(xiàn)
見下圖
從圖中看到BigDecimal的就是通過擴(kuò)大小數(shù)的倍數(shù)來計算的叙淌;
采用BCD方法
https://en.wikipedia.org/wiki/Binary-coded_decimal
總結(jié)記錄結(jié)束3诱啤!鹰霍!