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

时间:2018-07-29 17:55:31

标签: sql sql-server python-3.x floating-accuracy pypyodbc

在SQL Server中,我创建了一个SQL数据类型为float的聚合列(我添加,多个,求和等其他列的组合)。

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

在浮点数下方,我得到的最后两位数字是随机的-我尝试将其转换为十进制,然后将最后两位数字切掉。

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

在SSMS中,两者的结果均为:0.0020042890676442 600

请记住,这里的输入常量是我从python那里获取的,因此它们可能已经被修改了。我不能直接从sql中获取它们,因为很难获得计算异常,而且我也不知道如何重现它。

但是通过pypyodbc运行到python,有时结果是python十进制。第二个语句的值类型为0.0020042890676442 700 的十进制类型,因此它看起来确实是舍入而不是截断。 >

我还注意到sql中的计算结果并不总是相同,并且浮点数的最后一位存在不稳定性-不确定如何在语法上进行测试。

强制转换为浮点数的常量为:

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

结果:0.0020042890676442 7

用小数点表示并四舍五入:

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.0020042890676442 700

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

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

我尝试在python端截断np.float64,如下所示:Truncating decimal digits numpy array of floats

但是由于sql中的最后一个浮点数可以在e15和e19之间,因此除非我将所有内容都限制在e15,否则我无法设置一致的截断级别。

1 个答案:

答案 0 :(得分:3)

未定义聚合的处理顺序,就像未定义任何查询结果的顺序一样,除非您使用ORDER BY子句。对于float,顺序很重要。可以使用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))