我正在将数据从一个表插入到MariaDB数据库的另一个表中,第一个表中的列为FLOAT
,第二个表中的列为DOUBLE
。数据可以具有任意大小,精度和小数位的值。
这是我进行直接复制时这些值会发生什么:
INSERT INTO data2 (value) SELECT value FROM data1
为这些值赋予随机的额外有效数字:
FLOAT in data1 DOUBLE in data2
-0.000000000000454747 -0.0000000000004547473508864641
-122.319 -122.31932830810547
14864199700 14864220160
CAST(value AS DECIMAL(65,30))
生成与上面col 2完全相同的值,除了我看到尾随零。
但是我刚刚做
UPDATE data2 SET value = 14867199700 WHERE id = 133025046;
接受DOUBLE
值。
是否必须将所有值导出到SQL脚本并重新导入它们?有没有更好的方法?
尽管花了很多时间尝试解决这个问题,但尽管性质有限,但我离解决方案还差得很远。我可以看到这是困扰所有技术的问题,而不仅仅是MariaDB或数据库,因此我可能只是在某个地方错过了答案。 Stackoverflow拼命尝试使用我以前从未见过的新建议功能来指导解决方案,但不幸的是,它们与其他建议的答案一样没有帮助。
答案 0 :(得分:1)
您的测试用例有缺陷。您正在输入小数位数,而不是测试{em>只是 FLOAT
到DOUBLE
的传输。
UPDATE tbl SET double_col = float_col
将始终复制完全相同的值。这是因为DOUBLE
表示形式是FLOAT
表示形式的超集(53 VS 24位精度;等等)。
带小数位的字母:UPDATE tbl SET double_col = 123.456
将使数字不正确,因为从十进制四舍五入到DOUBLE
。 float_col
的同上。而且,错误的结果会有所不同!
孔号文字:UPDATE tbl SET double_col = 14867199700
将被精确存储。但是,如果将相同的文字放入FLOAT
中,则会将其舍入为24位,因此无法准确存储。对于FLOAT
,您失去了 about 7个有效数字的准确性;对于DOUBLE
,您失去了 about 16个有效数字。此示例中的文字有9个有效数字(忽略尾随零)。
那只是噩梦中的一部分。
您必须将FLOAT
和DOUBLE
视为近似。你永远不应该为了平等而比较。您不知道值的最后一位可能是什么问题。
此外,您不应尝试猜测MySQL何时将在DECIMAL
而非DOUBLE
中执行表达式。
并且要记住,由于四舍五入到一些位数或小数,除法通常是不精确的。
14864199700的“尾数”是
1.10111010111111001101100 (binary of FLOAT : 24 bits including 'hidden' leading bit)
1.1011101011111100110110000000101000000000000000000000 (binary of DOUBLE)
^ ^ (lost in FLOAT)
每一个都乘以2的相同乘方。DOUBLE
精确地为14864199700。FLOAT
丢失了所指向的位。
您可以在https://gregstoll.dyndns.org/~gregstoll/floattohex/上玩这样的游戏
信不信由你,事情以前一直很糟。由于四舍五入的错误,将向人们收取0.00美元的费用。或应为1 + 1的结果显示为1.99999999。