问题
This is somewhat related to the answer. I understand the float is not suggested for high precision. But I don't exactly get what's going on with FLOAT after going through the below results,
Observation 1
The value returned by the below 2 queries returns different results,
SELECT MY_FLOAT_COL FROM MY_TABLE;
SELECT MY_FLOAT_COL*1 FROM MY_TABLE;
The possible explanation is the reference in the above link, which says the float is approximate value and the problem is the datatype.
Observation 2
The queries
SELECT MY_FLOAT_COL*1 FROM MY_TABLE;
SELECT MY_FLOAT_COL FROM MY_TABLE;
returns the same result when I execute using Squirrel SQL(Java), but returns different results when executed through Heidi SQL(Object Pascal) and Python script. So this leads to a conclusion that the problem is with the client.
What exactly is going on with the Float
datatype of Mysql. I am trying to make sense of above 2 observations.
Edit: I care more about my Observation 2. I am able to make some sense out of my Observation 1 but the latter is mysterious as of now.
回答1:
When you multiply by 1
, the result is being converted to DOUBLE
. This has more precision, and as a result you can see the error in the decimal approximation. You can see the same thing by assigning a FLOAT
column to a DOUBLE
column.
CREATE TABLE `my_table` (
`my_float_col` float,
`my_double_col` double
);
INSERT INTO my_table (my_float_col) values (1.2355);
UPDATE my_table SET my_double_col = my_float_col;
SELECT my_float_col, my_double_col, my_float_col * 1 FROM my_table;
+--------------+--------------------+--------------------+
| my_float_col | my_double_col | my_float_col * 1 |
+--------------+--------------------+--------------------+
| 1.2355 | 1.2354999780654907 | 1.2354999780654907 |
+--------------+--------------------+--------------------+
I'm not really sure why it's returning DOUBLE
from the multiplication, because the documentation says:
If any of the operands of a
+
,-
,/
,*
,%
is a real or string value, the precision of the result is the precision of the operand with the maximum precision.
But it's clearly what's happening.
回答2:
What is happening can be explained with a slight modification to Barmar's answer which I have below:
drop table if exists my_table2;
CREATE TABLE `my_table2` (
`my_float_col` float(18,16), -- FLOAT(M,D)
`my_double_col` double(18,16)
);
INSERT INTO my_table2 (my_float_col) values (1.2355); -- 1.2354999780654907
UPDATE my_table2 SET my_double_col = my_float_col;
SELECT my_float_col, my_double_col, my_float_col * 1 FROM my_table2;
+--------------------+--------------------+--------------------+
| my_float_col | my_double_col | my_float_col * 1 |
+--------------------+--------------------+--------------------+
| 1.2354999780654907 | 1.2354999780654907 | 1.2354999780654907 |
+--------------------+--------------------+--------------------+
The float (column 1) for Barmar is a C float datatype just as mine is. But because he did not specify the precision (M,D)
, the internal implementation in C still pegs it as a C float, we have the same value, but the fact is lost in Barmar's. It is just that his display width rounds it up. Note the function I created below that can show that.
And check out this humorous MySQL Manual page entitled FLOAT and DOUBLE Data Type Representation and I think it will be very clear to anyone delving into it. Because we would, afterall, be math-heads anyway:
Let us now take up the story from where the MySQL Reference Manual leaves off.
The following discussion concentrates on the case where no display width and decimals are given. This means that FLOAT is stored as whatever the C type float is and REAL or DOUBLE [PRECISION] is stored as whatever the C type double is. The field length is selected by the MySQL code.
So despite Barmar's first column of output, it was never in there as a 1.2355
, and the above manual page cleverly and humorously describes the head-banging that people have gone through.
Helper fcn if of interest:
DROP FUNCTION IF EXISTS returnFloatFromDec;
DELIMITER $$
CREATE FUNCTION returnFloatFromDec(n DECIMAL(18,16))
returns FLOAT
BEGIN
DECLARE theRet FLOAT;
SET theRet=n; -- note that CAST can't take a FLOAT
return(theRet);
END;$$
DELIMITER ;
来源:https://stackoverflow.com/questions/39047486/whats-going-on-with-mysql-float