MySQL 存储函数中可以截断 FLOAT 类型吗?
Can FLOAT types be truncated in MySQL stored functions?
我是 MySQL 和存储函数的新手,如果这个问题看起来很初级,我深表歉意。
我正在编写一个存储函数,我需要在其中将浮点数截断到一定数量的小数位。据我了解,内置的 TRUNCATE 函数应该为我做这件事;但是,我得到的结果根本没有被截断。唯一值得注意的变化是预期截断点之后的某些数字与原始数字不同。
我已经尝试使用相同的数字(原始)单独试验截断函数,即。 SELECT TRUNCATE(0.00123456, 5) AS 'Example',并且按预期工作。我感觉存储函数中的问题与在截断函数中用作参数的浮点类型有关。
我应该指出,我首先截断这个数字的原因是 round 函数未能按预期截断小数位数的结果。我在这里对此进行了更多解释(并以实际功能为例):,但为了清楚起见,我在下面包含了一些精简代码。
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。
truncate 与 FLOAT 类型不兼容有什么原因吗?还是我在这里还缺少其他东西?
是的,它们不兼容。
FLOAT 以 IEEE-754 二进制格式存储数据,该格式存储在基数 2 中。基数 10 的分数不完全适合。因此,您的函数在截断时会得到接近 0.0012345 的值,但 FLOAT 无法保持准确的值,因此您会得到所需的数字。
有关 IEEE 格式浮点数的表示形式,请参阅许多答案 here and elsewhere especially What Every Computer Scientist Should Know About Floating-Point Arithmetic。
如果您想要精确的小数位数,您需要使用 DECIMAL 类型
我是 MySQL 和存储函数的新手,如果这个问题看起来很初级,我深表歉意。
我正在编写一个存储函数,我需要在其中将浮点数截断到一定数量的小数位。据我了解,内置的 TRUNCATE 函数应该为我做这件事;但是,我得到的结果根本没有被截断。唯一值得注意的变化是预期截断点之后的某些数字与原始数字不同。
我已经尝试使用相同的数字(原始)单独试验截断函数,即。 SELECT TRUNCATE(0.00123456, 5) AS 'Example',并且按预期工作。我感觉存储函数中的问题与在截断函数中用作参数的浮点类型有关。
我应该指出,我首先截断这个数字的原因是 round 函数未能按预期截断小数位数的结果。我在这里对此进行了更多解释(并以实际功能为例):
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。
truncate 与 FLOAT 类型不兼容有什么原因吗?还是我在这里还缺少其他东西?
是的,它们不兼容。
FLOAT 以 IEEE-754 二进制格式存储数据,该格式存储在基数 2 中。基数 10 的分数不完全适合。因此,您的函数在截断时会得到接近 0.0012345 的值,但 FLOAT 无法保持准确的值,因此您会得到所需的数字。 有关 IEEE 格式浮点数的表示形式,请参阅许多答案 here and elsewhere especially What Every Computer Scientist Should Know About Floating-Point Arithmetic。
如果您想要精确的小数位数,您需要使用 DECIMAL 类型