SQL Server浮动不稳定的最后一位数字



在SQL Server中,我创建了一个聚合列(我添加的其他列、multiple、sum等的组合(,该列的SQL数据类型为float。

但是,当我多次运行同一个查询时,浮点值的最后两位数字是不稳定的,并且不断变化。

在浮动下面,我得到了随机的最后两位数字——我试图转换为十进制,然后切掉最后两位。

select round(convert(decimal(20,19), 0.0020042890676442646), 17,1)
select round(convert(decimal(20,19), 0.0020042890676442654), 17,1)

在SSMS中,两者的结果均为:0.0020042890676442600,如预期。

请注意,这里的输入常量是我从python中获取的,所以它们可能已经被修改了。我不能直接从sql中获取它们,因为获得计算异常的情况非常罕见,而且我不知道如何重现。

但通过pypyodbc将其运行到python,有时结果是python十进制。值为0.0020042890676442的十进制类型700用于第二个语句,因此它似乎确实进行了舍入而不是截断。

我还注意到,sql中的计算结果并不总是相同的,并且在浮点的最后一位数字中存在不稳定性——但不确定如何对其进行系统测试。

投射到浮点的常量给出:

select convert(float,0.0020042890676442646)
select convert(float,0.0020042890676442654)

结果:0.00200428906764427

用小数包装并四舍五入:

select round(convert(decimal(20,19), convert(float,0.0020042890676442646)), 17,1)
select round(convert(decimal(20,19), convert(float,0.0020042890676442654)), 17,1)

SSMS的结果是:在这两种情况下,0.0020042890676442700

我尝试直接发回浮点值,而不是强制转换为十进制,但当到达python时,似乎总是在末尾添加两个不稳定的数字。即使截断也无济于事,然后添加其他随机数。

在传输过程中,python似乎以随机的方式同时修改了float和Decimal,或者不稳定性已经存在于sql中,或者两者都存在。

我试着在python端截断np.float64,如下所示:截断浮点的十进制数字numpy数组

但是由于sql中的最后一个浮点数字可能在e15和e19之间,所以我不能设置一致的截断级别,除非我将所有内容都设置为e15。

聚合的处理顺序未定义,就像任何查询的结果顺序未定义一样,除非使用ORDER BY子句。在floats的情况下,顺序很重要。聚合处理的顺序可以使用OVER子句强制执行。以下是一些要演示的代码:

-- demonstrate that order matters when adding floats
declare @a float
declare @b float
declare @c float
declare @d float
declare @e float
set @a = 1
set @b = 1
set @c = 9024055778268167
-- add A to B, and then add C
-- result is 9024055778268170
set @d = @a + @b
set @e = @d + @c
select cast( @e as decimal(38,0) )
-- add C to B, and then add A
-- result is 9024055778268168
set @d = @c + @b
set @e = @d + @a
select cast( @e as decimal(38,0) )
-- put these values into a table
create table OrderMatters ( x float )
insert into OrderMatters ( x ) values ( @a )
insert into OrderMatters ( x ) values ( @b )
insert into OrderMatters ( x ) values ( @c )
declare @x float
-- add them in ascending order
-- result is 9024055778268170
select @x = sum(x) over (order by x asc ) from OrderMatters
select cast(@x as decimal(38,0))
-- add them in descending order
-- result is 9024055778268168
select @x = sum(x) over (order by x desc ) from OrderMatters
select cast(@x as decimal(38,0))

相关内容

  • 没有找到相关文章

最新更新