浮點數精度

一、爲何叫浮點數?
   相對於浮點數,就是固點數,小數點固定在最右邊,也就是整數。浮點數的小數點,根據指數的取值,左右移動。
二、考慮二進制整數,假設只有2個bit,能夠表示00,01,10,11,共四個整數,表示範圍是[0,3],能夠表示這個範圍內的全部整數。
三、考慮二進制小數,假設只有2個bit,能夠表示多少個小數?   答案也是四個。假設小數點在最左邊,分別爲00,01,10,11,表示的值分別爲0.0,0.25,0.50,0.75。表示範圍[0.0,0.75],特別注意:不一樣於整數,整數能夠表示範圍內的每個整數,如[0,3]。而小數只能表示[0.0, 0.75]範圍內的四個小數,咱們知道從0.0到0.75有無數個小數,兩位二進制只能表示其中的4個。
四、十進制0.0到0.9,有幾個可使用二進制表示?
   只有兩個,0.0和0.5。考慮十進制,小數第一位是1/10,小數第二位是1/100,小數第三位是1/1000,那麼二進制呢?
   小數第一位是1/2,小數第二位是1/4,小數第三位是1/8,那麼0.1 可使用下面的方式表示嗎?
   a1*1/2 + a2*1/4 + a3*1/8 + ....
   存在這樣的a1,a2,a3嗎?
   答案是不存在。
五、0.1+0.2 爲何不等於0.3?而是0.30000000000000004
   在計算的時候,計算機要把0.1和0.2轉化爲二進制表示,由上面分析,咱們知道計算機沒法準確表示0.1和0.2,只能是無限接近地表示,那麼無限接近0.1和0.2的兩個值相加,固然不能保證是0.3,可是能夠保證的是,結果無限接近0.3。
六、那麼怎麼解釋 0.2+03 會等於0.5呢?
舉個例子,計算 1.6+1.8,如今假設不能準確表示1.6和1.8,只能準確表示整數,先轉化爲最接近的整數,也就是2+2=4,這與1.6+1.8=3.4,再轉化爲最接近的3,相差爲1。那麼是否是,全部的計算結果都不許確呢?
不是這樣,考慮1.2+1.8 =3,轉化爲處理是 1+2 =3,計算的結果是準確的。
也就是說,轉化過程當中精度缺失,若是兩個加數都多了一點,其和多了一點加一點。若是一個加數多了一點,一個加數少了一點,恰好相互抵消,其和恰好很是準確,一點不差。
七、二進制與十進制的轉化,
   二進制整數轉爲十進制整數,二進制小數轉爲十進制小數都簡單。
   十進制整數轉爲二進制小數,除2取餘,倒序排列。
   十進制小數轉爲二進制小數,乘2取整,順序排列。用這種方法,能夠知道0.1永遠不能獲得0
八、思考一下,十進制小數0.1不能用二進制準確表示,那麼是否是全部的二進制小數,均可以使用十進制準確表示呢?
能夠。二進制小數,轉爲十進制,就是a1/2+a2/4+a3/8....,a1,a2,a3取值爲0或者1,那問題就轉化爲,1除2的n次方,是否是都能除盡。類推一下,0.5,0.25,0.125,每次末位都是5,除2結尾是25,永遠都能除盡。

九、從數學的角度分析,對於小數,2進制只能表示1/2,  3進制只能表示1/3, 2/3, 3進制無法表示1/2, 也就是一半,你會說1.5/3 就是一半呀,這就是一個遞歸的問題,那1.5怎麼用3進製表示?無法表示。那麼10進制,只能表示1/10, ...9/10,  而恰巧5/10就是1/2, 所以10進制可以表示2進制的任何小數。 spa

十、若是我想讓0.1+0.2 等於0.3,怎麼辦?
從上面分析知道,二進制能夠表示可表示範圍內的任意一個整數。咱們把0.1和0.2根據小數點分紅兩部分,同時記住小數點的位置。,分別變成整數相加,再合併進位,在字符串中添加小數點的位置便可。須要注意的是:小數點左邊右對齊,小數點右邊左對齊。好比:12.46+5.5400,分別爲12+5,4600+5400。
代碼以下:
string NzbUtils::GetRightDouble(string a, string b)
{
vector<string> aVec;
StringSplit(a,".",aVec,true);
vector<string> bVec;
StringSplit(b,".",bVec,true);
int c1 =  atoi(aVec[0].c_str()) + atoi(bVec[0].c_str());
int maxLen = aVec[1].size() > bVec[1].size() ? aVec[1].size():bVec[1].size();
if(maxLen > aVec[1].size())
{
while(maxLen > aVec[1].size())
{
aVec[1]+="0";
}
}
if(maxLen > bVec[1].size())
{
while(maxLen > bVec[1].size())
{
bVec[1]+="0";
}
}
int c2 =  atoi(aVec[1].c_str()) + atoi(bVec[1].c_str());
char ch[64] = {0};
sprintf(ch,"%d",c2);
if(strlen(ch) > aVec[1].size())
{
c2 = atoi(ch+1);
c1 = c1+1;
}
char ret[64] = {0};
sprintf(ret,"%d.%d",c1,c2);
return ret;
}
相關文章
相關標籤/搜索