2

在 SQL Server 2008 中,我在 XML 属性中有值“0.01”。使用 OPENXML,我将 XML 分解成一个临时表。如果适用列的类型为 real(单精度),则在表中显示为 0.01。好的。但是,如果精度是浮点数(双精度),则结果为 0.00999999977648258。这是没有意义的。为什么要这样做?

我的下一个问题是,无论临时表中的值如何表示,当我对其运行聚合函数时,它总是返回为 0.00999999977648258。这会导致验证错误:程序报告输入太小(< 0.01),这是不正确的。

任何想法为什么会发生这些舍入错误以及如何克服它们?

已经尝试过:使列成为 varchar。

编辑2:

根据答案,我理解问题是由于 IEEE 数字不能准确表示 0.01。因此我的下一个问题:

“WHERE {computed} < 0.01”,为什么 0.01 也没有在这里四舍五入?如果是,方程将按预期计算(即 0.00999999977648258 不小于 0.00999999977648258)

编辑:显示的示例代码

此代码将产生错误。将指示的浮点数更改为实数,错误“消失”。至少就临时表而言。

DECLARE @XMLText varchar(max)

SET @XMLText = 
'<query prodType="1">
  <param type="1" lowMin="10" hiMax="300">
    <item low="18" hi="20" mode="1" weight="1" />
    <item low="220" hi="220" mode="0" weight="1" />
  </param>
  <param type="2" lowMin="4" hiMax="6">
    <item low="5" hi="5" mode="1" weight="1" />
    <item low="6" hi="6" mode="0" weight="0.01" />
  </param>
  <param type="3" lowMin="0" hiMax="300">
    <item low="34" hi="34" mode="1" weight="0.75" />
    <item low="40" hi="60" mode="1" weight="0.25" />
  </param>
</query>'

DECLARE @hxml int, @sp INT, @StartXCount int

EXEC sp_xml_preparedocument @hxml OUTPUT, @XMLText

IF @sp != 0 BEGIN
    SET @Result = '0'
    RETURN
END

DECLARE @t table (
    LowMin         real,
    HiMax          real,
    ParamTypeID    int,
    ParamWeight    float, -- real <<<
    Low            real,
    Hi             real,
    Mode           tinyint          
)

INSERT INTO @t
SELECT      *
FROM        OPENXML (@hxml, '/query/param/item', 2)
WITH        (
                LowMin       real     '../@lowMin',
                HiMax        real     '../@hiMax',
                ParamTypeID  int      '../@type',
                ParamWeight  real     '@weight',
                Low          real     '@low',
                Hi           real     '@hi',
                Mode         tinyint  '@mode'
            )

SELECT * FROM @t
4

2 回答 2

1

0.01不能完全存储在一个IEEE类型中,因为它不能用分母幂的分数表示2

但是,我可以重现的内容与您所说的相反:

SELECT  CAST(0.01 AS FLOAT) AS value
FOR XML PATH(''), TYPE

<value>1.000000000000000e-002</value>

 

SELECT  CAST(0.01 AS REAL) AS value
FOR XML PATH(''), TYPE

<value>9.9999998e-003</value>

您能否发布您的确切查询?

更新:

我用你的代码得到了同样的结果:0,01什么时候ParamWeightFLOAT0,00999999977648258什么时候是REAL

更新 2:

IEEE类型存储为符号、尾数和有效数。对于一个32-bit值,尾数是2的最大幂的二进制对数(小于该值),一个有效数是一个23-bit二进制小数(从1到的数字2,前导1不存储。)。

在您的情况下,它-7用于尾数(2^-7 = 1/128 = 0,0078125)1.01000111101011100001010有效数字(= 1 + 2348810 / 8388608 = 1,2799999713897705078125)

结果数字是这些数字的乘积,接近0.01但仍不够接近以避免15第 ' 位错误(精度SQL Server认为很重要)

于 2010-12-24T12:27:00.657 回答
1

该错误是因为计算机不能以单精度和双精度浮点表示值 0.01。该值以浮点数和双精度数四舍五入到最接近的可表示值。所以在这两种情况下它都不是 0.01,而是在真实情况下只显示为 0.01(我不知道浮点的 ToString 算法是如何工作的,所以不能告诉你为什么它在一种情况下被转换为 0.01和 0.00999999977648258 在另一个)。

我唯一可以肯定地告诉你的是——在实际情况下,它被四舍五入到 0.01 以上的可表示值,而在双重情况下,它被四舍五入到 0.01 以下的可表示值。因此,在双精度情况下验证失败。

为了克服这个问题,对于一些非常小的 epsilon,您可以将验证测试更改为“小于 0.01 - epsilon”。

于 2010-12-24T12:31:09.820 回答