【发布时间】:2019-01-06 01:26:39
【问题描述】:
在 SQL Server 中,我创建了一个聚合列(我添加的其他列、多个列、总和等的组合),它是 SQL 数据类型 float。
但是,当我多次运行相同的查询时,我的浮点数的最后 2 位数字不稳定并不断变化。
在我得到随机最后两位数字的浮点数下方 - 我尝试转换为十进制,然后去掉最后两位数字。
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 decimal.Decimal 类型,第二个语句的值为 0.0020042890676442700,所以它似乎做舍入而不是截断。
我还注意到 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在传输过程中以随机方式同时修改了浮点数和小数点,或者不稳定性已经存在于sql中或两者兼而有之。
我尝试像这样在 python 端截断 np.float64:Truncating decimal digits numpy array of floats
但由于 sql 中的最后一个浮点数可以在 e15 和 e19 之间,我无法设置一致的截断级别,除非我将所有内容都设置为 e15。
【问题讨论】:
-
。 .我认为您的代码中没有任何浮点数。我认为,常量被解释为小数。
-
您可以看到使用
sp_describe_first_result_setSQL Server 将这两个文字解释为numeric(19,19):EXEC sp_describe_first_result_set N'SELECT 0.0020042890676442646'; EXEC sp_describe_first_result_set N'SELECT 0.0020042890676442654';。看来python在你背后做点什么。 -
第一个问题是,为什么聚合在不同的时间会给出不同的答案?在计算聚合时,不能保证每次都以相同的顺序处理记录,就像在任何查询中都不能保证顺序一样,除非您使用 ORDER BY。在浮点数上进行数学运算时,顺序可能很重要。如果您有一个浮点数列表并从最小值开始添加,则与从最大值开始添加时会得到不同的答案。
-
浮点数在 SQL Server 中只能精确到 15 位。如果你有更多,精度将会丢失。这是记录在案的。
-
@KaiAeberli - 小数点分隔符后有 17 位数字,但前两个零不是 有效数字,它们只是浮点数缩放(指数)的结果值:2.00428906764426E-3
标签: sql sql-server python-3.x floating-accuracy pypyodbc