SQL开发知识:浅谈sqlserver下float的不确定性

1. 引言

在SQL Server中,float数据类型是一种十进制浮点数,它可以存储一个小数或极其小或极其大的数字。而在使用float类型时,我们需要注意其中存在的一些不确定性。

2. 浮点数存储方式

2.1. 二进制存储

计算机中的浮点数是以二进制形式表示的,其存储方式是:

s e f

+-+---+-----------------+

|1|8-7| 22-0 |

+-+---+-----------------+

其中s表示符号位(正数为0,负数为1),e表示阶码,f表示尾数。具有n位尾数的二进制浮点数p表示为:

p = (-1)^s * 1.f * 2^e

由此可见,浮点数的存储格式与其值本身是分离的。

2.2. 浮点数的精度问题

由于浮点数的表达式中,一部分存储空间表示小数点移动的位置(称为“阶码”),另一部分用于表示实际数值(称为“尾数”)。阶码和尾数的位数都是有限的,因此存储值的精度也是有限的。例如,当阶码只有8位时,即使尾数有22位,也只能表示2^8=256个不同的值,因此不能准确表示所有的浮点数值。

3. SQL Server下float的不确定性

3.1. 浮点数值比较的问题

在SQL Server中,由于float类型的不确定性,使用等号(“=”)进行相等判断时,可能会出现问题:

SELECT CASE WHEN 0.1+0.2=0.3 THEN 'TRUE' ELSE 'FALSE' END AS Result

-- Output: FALSE

这是由于float类型在进行算术运算时,可能会产生微小的舍入误差,导致两个看似相等的值不相等。

因此,在SQL Server中比较float类型的数值应使用“!=”或“>=”等比较符:

SELECT CASE WHEN ABS((0.1+0.2)-0.3) <= 0.0001 THEN 'TRUE' ELSE 'FALSE' END AS Result

-- Output: TRUE

该语句将0.1、0.2、0.3的和与期望的0.3做差,判断差的绝对值是否在一定误差范围内。

3.2. 浮点数值舍入的问题

另一个常见问题是,float类型在进行舍入操作时,可能会导致数值出现误差。例如:

SELECT CAST(3.555 AS FLOAT) -- Output: 3.5550000667572

在进行类型转换时,SQL Server使用四舍五入法将小数部分舍入为16位精度的二进制数。由于浮点数只能精确表示2的幂次方分之一的小数,因此可能会出现类似的微小误差。

4. 总结

在SQL Server中使用float类型需要注意其存在的不确定性。为了避免浮点数值比较或舍入时产生误差,建议使用比较符或精确小数类型(如DECIMAL或NUMERIC)。

数据库标签