私は、浮動小数点値1223473をMySQLの浮動小数点列に挿入し、戻すと値が1223470に変わります。ここでMySQLが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クライアントを使用して見られています。
入力値が出力と同じではない理由を説明できませんでした。さらに、なぜオペレーションを適用することで正しい価値が得られるのでしょうか?他の値を指定しても、私は同じ動作をします。たとえば、122473の代わりに1223472を使用すると、出力値は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)
なぜ値が変更されますか?
私は、Java floatがこの数値を表現するのに十分であっても、MySQLのfloatの精度が不十分だと考えます。 –
私が理解していないのは、その上に操作を適用するときに初期値が戻ってくる理由です。私はこれをより良く示すために私の質問を編集しました。 –
追加情報を追加しました。 SUMの場合、AVG:これらの関数はdoubleを返します。 「結果を保持できる」データが他のものと一緒に返されることを強く疑う。 doubleを 'float(8,1)'に変更すると、問題が解決されます。結論:浮動小数点型を使用するときは、値を保持するのに十分な大きさのデータ型を持っていることを確認し、それ以外の場合は 'decimal' – jhenderson2099