select POWER(2.,64.)
返回18446744073709552000
而不是18446744073709551616
. 它似乎只有 16 位精度(四舍五入)。
即使使精度明确select power(cast(2 as numeric(38,0)),cast(64 as numeric(38,0)))
,它仍然返回舍入结果。
这似乎是一个非常基本的操作,因为它可以像这样以 16 位精度任意剥落。它可以正确计算的最高值只是POWER(2.,56.)
,失败了POWER(2.,57.)
。这里发生了什么?
真正可怕的是它select 2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.;
实际上返回了正确的值。简洁明了。
从在线文档:
这意味着无论您作为第一个参数传递的任何内容都将在函数执行
float(53)
之前被隐式转换为 a 。但是,情况并非(总是?)。如果是这种情况,它将解释精度的损失:
另一方面,字面
2.
量是类型numeric
……:dbfiddle在这里
…并且乘法运算符返回具有更高优先级的参数的数据类型。
似乎在 2016 (SP1) 上保留了所有精度:
dbfiddle在这里
…但在 2014 (SP2) 上,它们不是:
dbfiddle在这里
2 64
float
的结果在(和real
就此而言)完全可以表示。当这个精确的结果被转换回
numeric
(第一个POWER
操作数的类型)时,问题就出现了。在引入数据库兼容级别 130 之前,SQL Server将隐式转换舍入
float
到最多 17 位。numeric
在兼容级别 130 下,在转换过程中会保留尽可能多的精度。这记录在知识库文章中:
SQL Server 2016 在处理某些数据类型和不常见操作方面的改进
要在 Azure SQL 数据库中利用这一点,您需要将其设置
COMPATIBILITY_LEVEL
为 130:需要进行工作负载测试,因为新安排不是万能的。例如:
...应该抛出一个错误,因为 10 38无法存储
numeric
(最大精度为 38)。120兼容性下出现溢出错误,但130下的结果是:通过一点数学,我们可以找到一种解决方法。对于奇数
n
:对于偶数
n
:在 T-SQL 中编写它的一种方法:
在 SQL Server 2008 上测试,结果是 144115188075855872 而不是 144115188075855870。
这一直有效到 113 的指数。看起来 NUMERIC(38,0) 最多可以存储 2 ^ 126,所以没有完全覆盖,但如果需要,公式可以分成更多部分.
只是为了好玩,递归 CTE 解决方案: