程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> mysql下float類型應用一些誤差詳解

mysql下float類型應用一些誤差詳解

編輯:MySQL綜合教程

mysql下float類型應用一些誤差詳解。本站提示廣大學習愛好者:(mysql下float類型應用一些誤差詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是mysql下float類型應用一些誤差詳解正文


單精度浮點數用4字節(32bit)表現浮點數
采取IEEE754尺度的盤算機浮點數,在外部是用二進制表現的
如:7.22用32位二進制是表現不下的。
所以就不准確了。

mysql中float數據類型的成績總結 

關於單精度浮點數Float:  當數據規模在±131072(65536×2)之內的時刻,float數據精度是准確的,然則超越這個規模的數據就不穩固,沒有發明有相干的參數設置建議:將float改成double或許decimal,二者的差異是double是浮點盤算,decimal是定點盤算,會獲得更准確的數據。

1.float類型
float列類型默許長度查不到成果,必需指定精度,
好比 num  float,  insert into  table (num) values (0.12); select  * from table where num=0.12的話,empty set。


num float(9,7),  insert into  table (num) values (0.12); select  * from table where num=0.12的話會查到這筆記錄。

mysql> create table tt
    -> (  
    -> num  float(9,3)
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql> insert into tt(num)values(1234567.8);
ERROR 1264 (22003): Out of range value for column 'num' at row 1

注:超越字段規模,沒法拔出
 

 代碼以下 復制代碼
mysql> insert into tt(num)values(123456.8);
Query OK, 1 row affected (0.00 sec)

mysql> select  * from  tt;
+------------+
| num        |
+------------+
| 123456.797 |
+------------+
1 row in set (0.00 sec) 

注:小數位數不敷,主動補齊,然則存在一個成績就是如上的近似值。
 

mysql> insert into tt(num)values(123456.867);
Query OK, 1 row affected (0.04 sec)

mysql> select * from   tt;
+------------+ 
| num        |
+------------+
| 123456.797 |
| 123456.797 |
| 123456.867 |
+------------+
3 rows in set (0.00 sec)

mysql> select  * from tt where  num=123456.867;
+------------+
| num        |
+------------+
| 123456.867 |
+------------+
1 row in set (0.00 sec)

mysql> insert into tt(num)values(2.8);
Query OK, 1 row affected (0.04 sec)

mysql> select * from   tt;
+------------+
| num        |
+------------+
| 123456.797 |
| 123456.797 |
| 123456.867 |
|      2.800 |
+------------+
4 rows in set (0.00 sec)

mysql> select  * from tt where  num=2.8;
+-------+ 
| num   |
+-------+
| 2.800 |
+-------+
1 row in set (0.00 sec)

mysql> insert into tt(num)values(2.888888);
Query OK, 1 row affected (0.00 sec)

mysql> select  * from  tt;
+------------+
| num        |
+------------+
| 123456.797 |
| 123456.797 |
| 123456.867 |
|      2.800 |
|      2.889 |
+------------+
5 rows in set (0.00 sec)

注:小數位數超了,主動取近似值。

1、浮點數的概念及誤差成績

浮點數是用來表現實數的一種辦法,它用 M(尾數) * B( 基數)的E(指數)次方來表現實數,絕對於定點數來講,在長度必定的情形下,具有表現數據規模年夜的特色。但同時也存在誤差成績,這就是有名的浮點數精度成績!浮點數有多種完成辦法,盤算機中浮點數的完成年夜都服從 IEEE754 尺度,IEEE754 劃定了單精度浮點數和雙精度浮點數兩種規格,單精度浮點數用4字節(32bit)表現浮點數,格局是:1位符號位 8位表現指數 23位表現尾數    雙精度浮點數8字節(64bit)表現實數,格局是:1位符號位 11位表現指數 52位表現尾數    同時,IEEE754尺度還對尾數的格局做了標准:d.dddddd...,小數點左面只要1位且不克不及為零,盤算機外部是二進制,是以,尾數小數點左臉部分老是1。明顯,這個1可以省去,以進步尾數的精度。由上可知,單精度浮點數的尾數是用24bit表現的,雙精度浮點數的尾數是用53bit表現的,轉換成十進制:
2^24 - 1 = 16777215;  2^53 - 1 = 9007199254740991
由上可見,IEEE754單精度浮點數的有用數字二進制是24位,按十進制來講,是8位;雙精度浮點數的有用數字二進制是53位,按十進制來講,是16 位。明顯,假如一個實數的有用數字跨越8位,用單精度浮點數來表現的話,就會發生誤差!異樣,假如一個實數的有用數字跨越16位,用雙精度浮點數來表現,也會發生誤差!關於 1310720000000000000000.66 這個數,有用數字是24位,用單精度或雙精度浮點數表現都邑發生誤差,只是水平分歧:  
單精度浮點數:1310720040000000000000.00;雙精度浮點數: 1310720000000000000000.00
可見,雙精度差了 0.66 ,單精度差了近4萬億!
以上解釋了因長度限制而形成的誤差,但這還不是全體!采取IEEE754尺度的盤算機浮點數,在外部是用二進制表現的,但在將一個十進制數轉換為二進制浮點數時,也會形成誤差,緣由是否是一切的數都能轉換成無限長度的二進制數。關於131072.32 這個數,其有用數字是8位,按理應當能用單精度浮點數精確表現,為何會湧現誤差呢?看一下這個數據二進制尾數就明確了 10000000000000000001010001......     明顯,其尾數跨越了24bit,依據捨入規矩,尾數只取 100000000000000000010100,成果就形成測試中碰到的“奇異”景象!131072.68 用單精度浮點數表現釀成 131072.69 ,緣由與此相似。現實上有用數字小於8位的數,浮點數也紛歧定能准確表現,7.22這個數的尾數就沒法用24bit二進制表現,固然在數據庫中測試不會有成績(捨入今後照樣7.22),但假如介入一些盤算,誤差積聚後,便可能發生較年夜的誤差。

2、mysql 和 oracle中的數值類型

成績是否是只要 mysql 存在呢?明顯不是,只需是相符IEEE754尺度的浮點數完成,都存在雷同的成績。
mysql中的數值類型(不包含整型):
IEEE754浮點數:float(單精度),double或real(雙精度)  
定點數:decimal或numeric
oracle中的數值類型:
oracle 浮點數 :number(留意不指定精度)  
IEEE754浮點數:BINARY_FLOAT(單精度),BINARY_DOUBLE(雙精度)FLOAT,FLOAT(n) (ansi請求的數據類型)
定點數:number(p,s)
假如在oracle中,用BINARY_FLOAT等來做測試,成果是一樣的。是以,在數據庫中,關於觸及泉幣或其他精度敏感的數據,應應用定點數來存儲,對mysql來講是 decimal,對oracle來講就是number(p,s)。雙精度浮點數,關於比擬年夜的數據異樣存在成績!

3、編程中也存在浮點數成績

不但數據庫中存在浮點數成績,編程中也異樣存在,乃至可以說更值得惹起留意!
經由過程下面的引見,浮點數的誤差成績應當比擬清晰了。假如在法式中做龐雜的浮點數運算,誤差還會進一步縮小。是以,在法式設計中,假如用到浮點數,必定要認識到能夠發生的誤差成績。不只如斯,浮點數假如處置欠好,還會招致法式BUG!看上面的語句:if (x != y) { z = 1 / (x -y);}這個語句看起來沒有成績,但假如是浮點數,便可能存在成績!再看上面的語句會輸入甚麼成果: public class Test { public static void main(String[]args) throws Exception { System.out.print("7.22-7.0=" + (7.22f-7.0f)); } }     我們能夠會想固然地以為輸入成果應當是 0.22 ,現實成果倒是 0.21999979 !
 是以,在編程中應盡可能防止做浮點數的比擬,不然能夠會招致一些潛伏的成績!除這些,還應留意浮點數中的一些特別值,如 NaN、+0、-0、+無限、-無限等,IEEE754固然對此做了一些商定,但各詳細完成、分歧的硬件構造,也會有一些差別,假如不留意也會形成毛病!

4、總結:

從下面的剖析,我們可以得出以下結論:

1、浮點數存在誤差成績;
2、對泉幣等對精度敏感的數據,應當用定點數表現或存儲;
3、編程中,假如用到浮點數,要特殊留意誤差成績,並盡可能防止做浮點數比擬;
4、要留意浮點數中一些特別值的處置

留意事項

MYSQL 5.022中,
假如某個字段 f是float類型,那末在查詢的時刻,sql語句為:
select * from T where f = 2.2;
那末即便表中有2.2的數據也不克不及被查詢到.

此時處理辦法有2種:
1.將float改成double類型,不會湧現這類成績.然則假如數據庫中數據量宏大,或許修正量太年夜,則不合適這個辦法.這個辦法只合適設計數據庫的早期階段.
2.設置float的精度然落後行查詢便可以了.
假如要准確到3位,則:select * from T where format(f,3) = format(2.2,3);

然則,精度不克不及跨越6.不然失足.由於float類型最多許可准確到小數點後6位.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved