在SQL Server 2008中,我在XML属性中具有值“0.01”。使用OPENXML,我将XML分解为临时表。如果适用的列是real(单精度)类型,则表中的值为0.01。好。但是,如果精度为float(双精度),则为0.00999999977648258。这毫无意义。为什么要这样做?
我的下一个问题是,无论值如何在临时表中表示,当我对其运行聚合函数时,它总是返回为0.00999999977648258。这导致验证错误:该过程报告输入太小(<0.01),这是不正确的。
为什么会出现这些舍入错误以及如何克服它们的任何想法?
已经尝试过:将列设为varchar。
EDIT2:
基于答案,我理解问题是由于IEEE数字不能精确地表示0.01。为此,我的下一个问题是:
“WHERE {computed}&lt; 0.01”,为什么会这样 0.01这里也不圆?如果是,那么等式将评估为 预期的(即0.00999999977648258是 不是&lt; 0.00999999977648258)
编辑:显示示例代码
此代码将产生错误。将指示的浮点数更改为实数&amp;错误“消失”。至少就临时表而言。
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
答案 0 :(得分: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
ParamWeight
为FLOAT
,0,00999999977648258
为REAL
。
更新2:
IEEE
种类型存储为符号,尾数和有效数字。对于32
- 位值,尾数是最大幂2的二进制对数(最小值),而有效数是23
- 位二进制分数(来自{{1的数字) }} 1
,未存储前导2
。)。
在您的情况下,尾数1
为-7
,有效数(2^-7 = 1/128 = 0,0078125)
为1.01000111101011100001010
。
结果数字是这些数字的乘积,接近(= 1 + 2348810 / 8388608 = 1,2799999713897705078125)
但仍然不够接近以避免0.01
'数字中的错误(精度15
认为重要)< / p>
答案 1 :(得分:1)
错误是由于计算机 CAN NOT 以单精度和双精度表示浮点值0.01。此值在float和double中四舍五入到最接近的可表示值。所以在这两种情况下它都不是0.01,但在实际情况下只显示为0.01(我不知道浮点运算的ToString算法是如何工作的,所以无法告诉你为什么在一种情况下它被转换为0.01和另一个中的0.00999999977648258。
我唯一可以告诉你的是 - 在实际情况下,它被舍入到可表示的值大于0.01,在双重情况下,它被舍入到可表示的值低于0.01。因此,在双精度情况下验证失败。
要解决此问题,您可以将某个非常小的epsilon的验证测试更改为“小于0.01 - epsilon”。