首页 > 解决方案 > 可以在 MySQL 存储函数中截断 FLOAT 类型吗?

问题描述

我是 MySQL 和存储函数的新手,所以如果这个问题看起来很简单,我深表歉意。

我正在编写一个存储函数,其中我需要将浮点数截断到一定数量的小数位。据我了解,内置的 TRUNCATE 函数应该为我执行此操作;但是,我得到的结果根本没有被截断。唯一值得注意的变化是预期截断点之后的一些数字与原始数字不同。

我已经尝试使用相同的数字(原始)自行尝试 truncate 函数,即。SELECT TRUNCATE(0.00123456, 5) AS 'Example',这和预期的一样。我感觉存储函数中的问题与在 truncate 函数中用作参数的浮点类型有关。

我应该注意到,我首先截断这个数字的原因是因为 round 函数未能按预期截断小数位数。我在这里解释更多(并以实际函数为例):MySQL 存储函数的正确 if 子句语法是什么?,但为了清楚起见,我在下面包含了一些精简的代码。

CREATE FUNCTION 'sfround'(number FLOAT, sigFigs INT) RETURNS FLOAT
DETERMINISTIC
BEGIN

DECLARE nonTruncated FLOAT;
DECLARE truncated FLOAT;
DECLARE decimalsKept INT;

#some not relevant code in the middle

SET nonTruncated = ROUND(number, sigFigs-1-FLOOR(LOG10(ABS(number))));
SET truncated = TRUNCATE(nonTruncated, decimalsKept);

RETURN truncated;

END$$

当我的输入是 1 到 -1 之间的任何数字(不包括 0,因为我包含了处理 0 的边缘情况)时,此函数会产生一个正确的数字,直到预期的截断点,之后看似不相关的数字列表出现(每次调用函数的数字相同)。

前任。sfround(0.00123456, 5) 产生 0.0012344999704509974。

截断与 FLOAT 类型不兼容有什么原因吗?还是我在这里缺少其他东西?

标签: mysqlfloating-pointtruncate

解决方案


是的,它们不兼容。

FLOAT 以 IEEE-754 二进制格式存储数据,该格式存储在基数 2 中。基数为 10 的分数不完全适合。因此,您的函数获得接近 0.0012345 的截断值,但 FLOAT 不能保持精确,因此您获得所需的数字。请参阅此处和其他地方的许多答案,尤其是每个计算机科学家应该知道的关于浮点运算的知识,以了解 IEEE 格式浮点数的表示形式。

如果你想有一个确切的小数位数,你需要使用DECIMAL类型


推荐阅读