Sql Server精度疯狂

时间:2010-11-16 21:49:48

标签: sql-server tsql precision

我遇到了sql server precision的问题。

我有以下疑问:

DECLARE @A numeric(30,10)
DECLARE @B numeric(30,10)
SET @A = 20.225
SET @B = 53.3875
SELECT @A * @B

DECLARE @A1 numeric(30,14)
DECLARE @B1 numeric(30,14)
SET @A1 = 20.225
SET @B1 = 53.3875
SELECT @A1 * @B1

DECLARE @A3 numeric(30,15)
DECLARE @B3 numeric(30,15)
SET @A3 = 20.225
SET @B3 = 53.3875
SELECT @A3 * @B3

DECLARE @A2 numeric(20,15)
DECLARE @B2 numeric(20,15)
SET @A2 = 20.225
SET @B2 = 53.3875
SELECT @A2 * @B2

DECLARE @A4 float
DECLARE @B4 float
SET @A4 = 20.225
SET @B4 = 53.3875
SELECT @A4 * @B4

分别产生以下结果:

1079.762188

1079.762188

1079.7621875

1079.762187500000000000000000000

1079.7621875

正确答案是:1079.7621875。

我不明白为什么,当类型具有相同的签名时,它们会失去精确度。另外,为什么从30,14到30,15会解决精度问题呢?另外,为什么20,15的小数位数比30,15小得多?

我已经阅读了这篇文章http://msdn.microsoft.com/en-us/library/ms190476(SQL.90).aspx,我认为我应该没事,因为我的变量具有相同的精度。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:3)

这在您粘贴的链接底部非常重要:

  
      
  • 结果精度和比例绝对最大值为38.   结果精度大于38,   相应的比例缩小为   防止结果的组成部分   被截断。
  •   

对于精度为30的所有结果,结果计算精度为61.由于可能的最大精度为38,因此精确度降低了23倍。因此,所有比例都降低了避免截断结果的整体部分,而不是绝对必要。

第二个到最后一个值,其中每个值的精度为20,结果精度为41,只需要减少3,从而可以减小比例部分。

(30,15)是有效的,因为结果比例为30,因此,当它减小时,它仍然足够大以保持你想要的值。

课程:不要使精度和比例大于你需要的大小,否则你会得到奇怪的结果。

答案 1 :(得分:2)

答案在于计算机如何在内部表示数字。根据您使用的精度,SQL Server将分配5,9,13或17个字节来表示您的数字(请参阅http://msdn.microsoft.com/en-us/library/ms187746(v=SQL.90).aspx)因此,例如,当您从精度30移动到精度20时,内部表示从17个字节到13个字节。如何在17字节数字上设置比例而不是13字节数字,其中数字表示的更大比例专用于比例(15/30 = 0.5,15 / 20 = 0.75,改变舍入行为。没有完美的答案我们拥有的数字类型对于大多数应用程序来说已经足够好了,但有时你会看到像我们看到的那样奇怪的文物,因为我们在计算机中代表数字时已经妥协了。

顺便说一下,浮动类型非常非常小心。它们只粗略地近似数字,并且在数量上使用时会给出非常错误的结果。当在一次计算中使用不超过约20个浮点数时,它们对于大多数科学应用是极好的。如果在数量上使用,比如在一个总和(column_name)中添加100万个浮点数,你就会得到垃圾。演示如下:

DECLARE @f FLOAT
DECLARE @n NUMERIC(20,10)
DECLARE @i INT

SET @f = 0
SET @n = 0
SET @i = 0

WHILE @i < 1000000
BEGIN
    SET @f = @f + 0.00000001
    SET @n = @n + 0.00000001
    SET @i = @i + 1
END

SELECT @n as [Numeric], @f as [Float]

这给了我关于SQL Server 2008的以下答案。

Numeric      Float
0.0100000000    0.00999999999994859