2017-09-15 51 views
0

我在MySQL浮動列中插入一個浮點值1223473,當我找回它時,該值更改爲1223470。爲什麼MySQL的float漂移與Java float不同?

import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.Statement; 

public class Main { 

    public static void main(String[] args) throws Exception { 

     Connection conn = null; 
     Statement stmt = null; 
     ResultSet rs = null; 
     PreparedStatement pstmt = null; 

     try { 
      // SETUP 
      Class.forName("com.mysql.jdbc.Driver"); 
      conn = DriverManager.getConnection("jdbc:mysql://..."); 

      stmt = conn.createStatement(); 
      stmt.execute("DROP TABLE IF EXISTS ttt"); 

      stmt.execute("CREATE TABLE ttt (value FLOAT)"); 

      // INPUT VALUE 
      float input = 1.223473E6f; 
      print(" Input", input); 
      pstmt = conn.prepareStatement("INSERT INTO ttt VALUES (?)"); 
      pstmt.setFloat(1, input); 
      pstmt.execute(); 

      // OUTPUT VALUES 
      rs = stmt.executeQuery("SELECT value, " 
        + "AVG(value) as avg, MIN(value) as min, " 
        + "MAX(value) as max, value + 0 as plus, " 
        + "value * 1 as mult, " 
        + "cast(value as decimal) as valcast " 
        + "FROM ttt;"); 
      rs.next(); 
      System.out.println(); 
      print("Output", rs.getFloat("value")); 
      print(" AVG", rs.getFloat("avg")); 
      print(" MIN", rs.getFloat("min")); 
      print(" MAX", rs.getFloat("max")); 
      print(" +0", rs.getFloat("plus")); 
      print(" *1", rs.getFloat("mult")); 
      print(" CAST", rs.getFloat("valcast")); 

     } finally { 
      if (stmt != null) 
       stmt.close(); 
      if (pstmt != null) 
       pstmt.close(); 
      if (conn != null) 
       conn.close(); 
     } 

    } 

    private static void print(String name, float value) { 
     System.out.println(name + ": " + value + " (0x" 
      + Integer.toHexString(Float.floatToRawIntBits(value)) + ")"); 
    } 

這裏是輸出:

Input: 1223473.0 (0x49955988) 

Output: 1223470.0 (0x49955970) 
    AVG: 1223473.0 (0x49955988) 
    MIN: 1223473.0 (0x49955988) 
    MAX: 1223473.0 (0x49955988) 
    +0: 1223473.0 (0x49955988) 
    *1: 1223473.0 (0x49955988) 
    CAST: 1223473.0 (0x49955988) 

相同的行爲是使用MySQL客戶端看到的。

我無法解釋爲什麼輸入值與輸出不相同。此外,爲什麼應用一項操作能夠提供正確的價值?即使有其他值,我也會得到相同的行爲。例如,如果我使用1223472而不是122473,則輸出值將爲1223470.它看起來像精確度的丟失。但爲什麼在其上應用操作會返回完全的輸入值?它看起來像MySQL存儲比它顯示的更精確。

它看起來並不像有關浮點類型,人們試圖把過多的數位在浮動的典型誤解:

System.out.println(1223473f == 1223470f); // gives false 
System.out.println(123456789f == 123456791f); // gives true (too many digits) 

最後,我不知道該怎麼想想...

mysql> create table ttt (value float); 
Query OK, 0 rows affected (0.04 sec) 

mysql> INSERT INTO ttt VALUES (1223473); 
Query OK, 1 row affected (0.00 sec) 

mysql> select * from ttt; 
+---------+ 
| value | 
+---------+ 
| 1223470 | 
+---------+ 
1 row in set (0.00 sec) 

mysql> SELECT * FROM ttt WHERE value = 1223470; 
Empty set (0.00 sec) 

mysql> SELECT * FROM ttt WHERE value = 1223473; 
+---------+ 
| value | 
+---------+ 
| 1223470 | 
+---------+ 
1 row in set (0.00 sec) 

爲什麼值發生變化?

回答

1

您正在使用float作爲數據類型。你沒有足夠的精度來表示1223473.0。根據MySQL documentation,浮點數也受「平臺或實施依賴性」的約束。

將列上的數據類型更改爲double(或decimal),這應該可以解決您的問題。請參閱this SQLFiddle進行確認。

當在floatdouble的值上執行時,聚合函數的值如SUM, AVG, return a double。從文檔中不清楚,但我強烈懷疑,當使用MIN,MAX,+ 0* 1也會導致可「保留結果值」的數據類型。

您應該意識到浮點操作應該在tolerance(即閾值)內進行,也是按照MySQL文檔的規定。

+0

我同意看起來MySQL float沒有足夠的精度,即使Java float已經足以表示這個數字。 –

+0

我不明白爲什麼初始值在應用操作時回來。我編輯了我的問題以更好地展示這一點。 –

+0

增加了一些額外的信息。對於SUM,AVG:這些函數返回一個double。我強烈懷疑可以「保留結果」的數據與其他數據一起返回。如果將double更改爲「float(8,1)」,那麼這也將解決您的問題。底線:當使用浮點類型時,確保你有一個足夠大的數據類型來保存你的值,否則使用'decimal' – jhenderson2099

相關問題