最近遇到乙個低階錯誤,哈哈,都不好意思講出來,會犯這種低階錯誤。寫此部落格,記錄我的低階錯誤,以防下次再犯。
問題是這樣的,我有一些float型別的資料,我需要將這這些浮點型資料放大到整數,然後轉換成int型別資料,比如float a=5.1 * 10就得到整數51,然後將浮點型資料51賦值給乙個int型資料:int b=static_cast(a),我滿以為b的結果就是51,然而事實給了我一記耳光,結果居然是50!我覺得很奇怪,這明明沒問題啊,不用電腦一眼就看出來就是51,怎麼會變成50?當我將a=5.2*10轉換成int時結果又變成51,而5.5*10轉換成int時結果又是對的,即55,這就更奇怪了。
後來查閱float型別資料的表示方法,才恍然大悟,原來float型別資料在計算機中是不能用二進位制精確表示的,計算機在計算浮點型資料的時候常常是不精確的。以上面的情況為例,浮點型資料5.1是由整數部分和小數部分組成,整數部分的二進位制為101,二進位制可以精確的表示;小數部分的表示如下:
0.1*2=0.2 取0
0.2*2=0.4 取0
0.4*2=0.8 取0
0.8*2=1.6 取1
0.6*2=1.2 取1
...
5.1=101.0001100110011001100110011...(計算過程可以查閱浮點數的二進位制表示,
可以看到小數部分是無限迴圈的,只有當小數部分為0.5是這個迴圈才結束,這就是為什麼計算機無法精確表示浮點數的原因,也是為什麼5.5*10轉換成int沒有出錯的原因。將101.0001100110011001100110011小數點左移到第乙個有效數字之後得到1.010001100110011001100110011...,從小數點後第一位開始數23位填充到float的尾數部分就得到float的尾數部分:01000110011001100110011,可見在這一步驟中又發生了一次不精確的取捨,小數點超出23位的部分捨去了,又損失了一次精度。上一步中移動了2位小數,因此指數部分為2+127=129,8位二進位制為10000001,由於5.1是正數,因此符號位為0,所以5.1的二進位制表示為:
0 10000001 01000110011001100110011
如果將上述二進位制浮點資料轉換成十進位制,首先最高位為0,表示正數,取前8位:10000001=129,減去127為2,取前2位尾數部分01,首位新增1得到:101,即整數部分為101=5,23位尾數去掉已取走的2位得到小數部分:000110011001100110011=1/2*0+1/4*0+1/8*0+1/16*1+1/32*1+...=5.0999(保留4位小數),可見浮點數5.1在計算機中並不是儲存的是5.1,而是乙個無限接近5.1的資料,有可能是5.099999904...,也有可能是5.10002136...等。
至此提出的問題已經很清晰了,5.1*10的結果有可能是50.99999904,而在static_cast轉int的時候,計算機是直接取整數部分,捨棄小數部分,因此結果就變成了50,而不是51。所以解決的方法就是四捨五入,或者是float資料加0.5再轉換成int.即static_cast(5.1*10+0.5)=51.
Access 轉 SQLite 注意事項
最近將乙個程式從access修改為sqlite,需要調整的地方整理如下。access 中可以直接使用數字開頭的表名稱,sqlite中不可以直接使用,表名要加雙引號,例如 select from 1table 1table前後要加雙引號,access中不用加雙引號 sqlite中沒有 now 函式,要...
Image轉Canvas注意事項
在寫影象上傳的時候,為了要統一影象的格式,所以難免要去將上傳的影象進行格式轉換。所以這裡就要用到canvas來轉換。這裡我們要使用filereader這個js預置物件,這個物件可以獲取到上傳的檔案資料,具體如下 html js function selectimage file var reader...
CAD轉CAD注意事項
剛處理一批資料,在visualizer裡面檢視結果好好的,數目也正確,可到輸出結果一看,亂七八糟,牛頭不對馬嘴,鬱悶了一陣子之後,開始找原因。是這樣 cad中的綠地只是簡單的用一系列綠地符號表示,綠地的邊界由各種線狀地物構成,包括房屋邊界線,道路邊界線等。此次欲將綠地邊界線提取出來,思路自然是將各類...