SQLite中如何规避浮点误差获取乘法运算的Floor值?
问题原因
这是浮点数二进制存储的精度限制导致的:像2102.7这类十进制小数,无法被二进制浮点数精确表示,实际存储的是一个略小于2102.7的近似值。当你将其乘以100000后,这个近似值会变成略小于210270000的数(比如210269999.99999994),而SQLite中CAST(xxx AS INTEGER)会直接截断小数部分,因此得到210269999,而非预期的210270000。
解决方案
方案1:极小偏移修正(适用于正数场景)
给计算结果加上一个极小的偏移量(比如1e-8,该值远小于浮点数的精度误差范围),再转换为整数,就能修正因精度问题导致的“略小于目标值”的情况:
SELECT CAST(2102.7 * 100000 + 1e-8 AS INTEGER); -- 结果:210270000
对于正常非整数(比如1.2*3=3.6),加偏移后仍小于4,截断后还是3,不影响正确结果。
方案2:通用floor实现(支持正负数值)
如果需要处理负数(floor对负数是向下取整,比如floor(-2.4) = -3,但CAST(-2.4 AS INTEGER)会得到-2,行为不符),可以用CASE语句实现完整的floor逻辑:
SELECT CASE WHEN x >= 0 THEN CAST(x + 1e-8 AS INTEGER) ELSE CAST(x - 1e-8 AS INTEGER) END AS floor_result FROM (SELECT 2102.7 * 100000 AS x);
负数场景下,减去极小偏移量能让略大于目标值的负数被截断到更小的整数,符合floor的向下取整要求。
方案3:整数运算彻底规避误差(固定小数位数场景)
如果你的小数列是固定小数位数(比如都是一位小数),可以先将所有数值转换为整数运算,从根源上消除浮点精度问题:
-- 把2102.7转为整数21027后运算,再还原小数位数 SELECT CAST((21027 * 100000) / 10 AS INTEGER); -- 结果:210270000
内容的提问来源于stack exchange,提问作者MSL
相关产品推荐
相关产品推荐

