Tsql 为什么圆形有时会产生额外的数字?

Tsql 为什么圆形有时会产生额外的数字?,tsql,Tsql,有时,当从数据库中选择聚合数据(通常是AVG())时,我会得到一个重复的小数点,例如: 2.7777777777777777 当我将舍入(AVG(x),2)应用于该值时,有时会得到如下结果: 2.7800000000000002 我碰巧知道,实际样本有18行,SUM(x)=50。所以这个命令应该是等效的: SELECT ROUND(50.0/18, 2) 但是,它会产生预期的结果()。为什么舍入有时会对聚合函数产生错误的结果 为了验证上述结果,我写了一个: 我知道,但这个简单的例子似乎不

有时,当从数据库中选择聚合数据(通常是
AVG()
)时,我会得到一个重复的小数点,例如:

2.7777777777777777
当我将
舍入(AVG(x),2
)应用于该值时,有时会得到如下结果:

2.7800000000000002
我碰巧知道,实际样本有18行,
SUM(x)
=50。所以这个命令应该是等效的:

SELECT ROUND(50.0/18, 2)
但是,它会产生预期的结果()。为什么舍入有时会对聚合函数产生错误的结果


为了验证上述结果,我写了一个:


我知道,但这个简单的例子似乎不受这些限制。

您的表使用浮点数。当给定浮点数作为参数时,
AVG()
ROUND()
都返回浮点数。浮动无法精确表示。当您执行
四舍五入(50.0/18,2)
时,您将给它
数值(8,6)
,它返回为
十进制(8,6)


尝试声明列以使用更精确的类型,如
DECIMAL(18,9)
。结果应该更加可预测。

您的表使用浮点数。当给定浮点数作为参数时,
AVG()
ROUND()
都返回浮点数。浮动无法精确表示。当您执行
四舍五入(50.0/18,2)
时,您将给它
数值(8,6)
,它返回为
十进制(8,6)


尝试声明列以使用更精确的类型,如
DECIMAL(18,9)
。结果应该更加可预测。

十进制数字并不总是(甚至通常)将1:1映射为浮点的精确表示

在您的例子中,双精度浮点可以表示的两个最接近的数字是

  • 约为2.77999999980460074766597
  • 约为2780000000024868995751604

这两个数字之间不存在双精度数字,在这种情况下,数据库选择了更高的值,如您所见,舍入为2.780000000000002。

十进制数字并不总是(甚至通常)将1:1映射为浮点的精确表示

在您的例子中,双精度浮点可以表示的两个最接近的数字是

  • 约为2.77999999980460074766597
  • 约为2780000000024868995751604

这两个数字之间不存在双精度数字,在本例中,数据库选择了更高的值,如您所见,该值舍入为2.780000000000002。

您肯定正确,问题源于
舍入()的参数类型(如中所示)。但是,我无法更改列的类型。我能够在查询本身中使用
round(avg(cast(x为decimal)),2)
。您肯定正确,问题源于
round()的参数类型(如中所示)。但是,我无法更改列的类型。我能够在查询本身中使用
round(avg(cast(x为十进制)),2)
,这是一个合理的解释。然而,这似乎是一个实现上的怪癖,因为其他SQL方言做了预期的事情:
sqlite3t.db“selectround(cast(25.0/9.0为double),2);”=>2.78这是一个合理的解释。然而,这似乎是一个实现上的怪癖,因为其他SQL方言做了预期的事情:
sqlite3t.db“selectround(cast(25.0/9.0为double),2);”=>2.78我以前经历过这种行为,但我认为这是出于设计。“这个简单的例子似乎不受[footchas of floating point representation]的约束。”一个非常快速的方法是使用其中一个。输入所需的值,然后检查结果表示形式。对于2.78,您会得到
2.779997979713897705
。您得到的值中似乎有太多的零。尝试一下@dasblinkenlight链接的计算器,我看到2.7799979713897705的二进制值是010000000011000111101110000101(作为双精度)。增加到01000000001100011110101110010110将产生一个十进制值2.7800002?!?这是否意味着无法存储2.779997979713897705和2.7800002之间的任何值?当然,这两者之间的间隔有二进制表示。在这种情况下,应该有一种更精确的取整方法。我以前经历过这种行为,但认为它是故意的。“这个简单的例子似乎不受[footpoint representation]的约束。”一种非常快速的方法是使用其中一种。输入所需的值,然后检查结果表示形式。对于2.78,您会得到
2.779997979713897705
。您得到的值中似乎有太多的零。尝试一下@dasblinkenlight链接的计算器,我看到2.7799979713897705的二进制值是010000000011000111101110000101(作为双精度)。增加到01000000001100011110101110010110将产生一个十进制值2.7800002?!?这是否意味着无法存储2.779997979713897705和2.7800002之间的任何值?当然,这两者之间的间隔有二进制表示。在这种情况下,应该有一种更精确的方法。
declare @temp table(
  x float
)

insert into @temp values (1.0);
insert into @temp values (2.0);
insert into @temp values (1.0);
insert into @temp values (1.0);
insert into @temp values (1.0);
insert into @temp values (1.0);
insert into @temp values (1.0);
insert into @temp values (8.0);
insert into @temp values (9.0);

select round(avg(x), 2),
       sum(x),count(*)
from @temp