萬盛學電腦網

 萬盛學電腦網 >> 數據庫 >> mysql教程 >> mysql float精度與范圍總結

mysql float精度與范圍總結

FLOAT類型用於表示近似數值數據類型。SQL標准允許在關鍵字FLOAT後面的括號內選擇用位指定精度(但不能為指數范圍)。MySQL還支持可選的只用於確定存儲大小的精度規定。0到23的精度對應FLOAT列的4字節單精度。24到53的精度對應DOUBLE列的8字節雙精度。

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

mysql中float數據類型的問題總結 
 
對於浮點列類型,在MySQL中單精度值使用4個字節,雙精度值使用8個字節。

FLOAT類型用於表示近似數值數據類型。SQL標准允許在關鍵字FLOAT後面的括號內選擇用位指定精度(但不能為指數范圍)。MySQL還支持可選的只用於確定存儲大小的精度規定。0到23的精度對應FLOAT列的4字節單精度。24到53的精度對應DOUBLE列的8字節雙精度。

MySQL允許使用非標准語法:FLOAT(M,D)或REAL(M,D)或DOUBLE PRECISION(M,D)。這裡,“(M,D)”表示該值一共顯示M位整數,其中D位位於小數點後面。例如,定義為FLOAT(7,4)的一個列可以顯示為-999.9999。MySQL保存值時進行四捨五入,因此如果在FLOAT(7,4)列內插入999.00009,近似結果是999.0001。

MySQL將DOUBLE視為DOUBLE PRECISION(非標准擴展)的同義詞。MySQL還將REAL視為DOUBLE PRECISION(非標准擴展)的同義詞,除非SQL服務器模式包括REAL_AS_FLOAT選項。

為了保證最大可能的可移植性,需要使用近似數值數據值存儲的代碼應使用FLOAT或DOUBLE PRECISION,不規定精度或位數。

DECIMAL和NUMERIC類型在MySQL中視為相同的類型。它們用於保存必須為確切精度的值,例如貨幣數據。當聲明該類型的列時,可以(並且通常要)指定精度和標度;例如:

salary DECIMAL(5,2)
在該例子中,5是精度,2是標度。精度表示保存值的主要位數,標度表示小數點後面可以保存的位數。

在MySQL 5.1中以二進制格式保存DECIMAL和NUMERIC值。

標准SQL要求salary列能夠用5位整數位和兩位小數保存任何值。因此,在這種情況下可以保存在salary列的值的范圍是從-999.99到999.99。

在標准SQL中,語法DECIMAL(M)等價於DECIMAL(M,0)。同樣,語法DECIMAL等價於DECIMAL(M,0),可以通過計算確定M的值。在MySQL 5.1中支持DECIMAL和NUMERIC數據類型的變量形式。M默認值是10。

DECIMAL或NUMERIC的最大位數是65,但具體的DECIMAL或NUMERIC列的實際范圍受具體列的精度或標度約束。如果此類列分配的值小數點後面的位數超過指定的標度允許的范圍,值被轉換為該標度。(具體操作與操作系統有關,但一般結果均被截取到允許的位數)。


二、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)。雙精度浮點數,對於比較大的數據同樣存在問題!
三、編程中也存在浮點數問題
不光數據庫中存在浮點數問題,編程中也同樣存在,甚至可以說更值得引起注意!
通過上面的介紹,浮點數的誤差問題應該比較清楚了。如果在程序中做復雜的浮點數運算,誤差還會進一步放大。因此,在程序設計中,如果用到浮點數,一定要意識到可能產生的誤差問題。不僅如此,浮點數如果處理不好,還會導致程序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雖然對此做了一些約定,但各具體實現、不同的硬件結構,也會有一些差異,如果不注意也會造成錯誤!四、總結:
從上面的分析,我們可以得出以下結論:
1、浮點數存在誤差問題;
2、對貨幣等對精度敏感的數據,應該用定點數表示或存儲;
3、編程中,如果用到浮點數,要特別注意誤差問題,並盡量避免做浮點數比較;
4、要注意浮點數中一些特殊值的處理。

實例

為了能夠引起大家的重視,在介紹浮點數與定點數以前先讓大家看一個例子:

 代碼如下 復制代碼 mysql> CREATE TABLE test (c1 float(10,2),c2 decimal(10,2));
Query OK, 0 rows affected (0.29 sec)
mysql> insert into test values(131072.32,131072.32);
Query OK, 1 row affected (0.07 sec)
mysql> select * from test;
+-----------+-----------+
| c1| c2|
+-----------+-----------+
| 131072.31 | 131072.32 |
+-----------+-----------+
1 row in set (0.00 sec)

從上面的例子中我們看到c1列的值由131072.32變成了131072.31,這就是浮點數的不精確性造成的。
在mysql中float、double(或real)是浮點數,decimal(或numberic)是定點數。
浮點數相對於定點數的優點是在長度一定的情況下,浮點數能夠表示更大的數據范圍;
它的缺點是會引起精度問題。

 Float類型和double類型的區別

FLOAT[(M,D)]   [ZEROFILL]  
一個小(單精密)浮點數字。不能無符號。允許的值是-3.402823466E+38到-1.175494351E-38,0   和1.175494351E-38到3.402823466E+38。M是顯示寬度而D是小數的位數。沒有參數的FLOAT或有 <24   的一個參數表示一個單精密浮點數字。  
DOUBLE[(M,D)]   [ZEROFILL]  
一個正常大小(雙精密)浮點數字。不能無符號。允許的值是-1.7976931348623157E+308到-2.2250738585072014E-308、   0和2.2250738585072014E-308到1.7976931348623157E+308。M是顯示寬度而D是小數位數。沒有一個參數的DOUBLE或FLOAT(X)(25   <   =   X   <   =   53)代表一個雙精密浮點數字。

copyright © 萬盛學電腦網 all rights reserved