2

SQL Server 2008 では、XML 属性に値 "0.01" があります。OPENXML を使用して、XML を一時テーブルに分割します。該当する列が実数型(単精度)の場合、表では0.01と出てきます。良い。ただし、精度が float (倍精度) の場合は、0.00999999977648258 となります。これは意味がありません。なぜこれを行うのですか?

次の質問は、値が一時テーブルでどのように表現されているかに関係なく、集計関数を実行すると、常に 0.00999999977648258 として返されるということです。これにより、検証エラーが発生しています。プロシージャは、入力が小さすぎる (< 0.01) と報告していますが、これは正しくありません。

これらの丸め誤差が発生する理由とそれらを克服する方法はありますか?

すでに試しました:列をvarcharにします。

EDIT2:

回答に基づいて、問題は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.01IEEE分母のべき乗を持つ分数では表現できないため、型に正確に格納することはできません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,01when ParamWeightis FLOAT0,00999999977648258when it's REAL.

更新 2:

IEEE型は、符号、仮数、仮数として格納されます。-32ビットの値の場合、仮数は 2 の最大べき乗の 2 進対数 (値よりも小さい) であり、仮数は -23ビットの 2 進小数 ( ~ の数値12、先頭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 を表すことができないために発生します。この値は、float と double の両方で最も近い表現可能な値に丸められます。したがって、どちらの場合も 0.01 ではなく、実際には 0.01 としてのみ表示されます (浮動小数点の ToString アルゴリズムがどのように機能するのかわかりません。そのため、1 つのケースでなぜ 0.01 に変換されるのかわかりません)。と 0.00999999977648258 別)。

私が確実に言える唯一のことは、実際のケースでは0.01を超える表現可能な値に丸められ、二重のケースでは0.01未満の表現可能な値に丸められたことです。したがって、倍精度の場合は検証に失敗しました。

この問題を克服するには、検証テストを変更して、いくつかの非常に小さなイプシロンに対して「0.01 - イプシロンよりも小さい」ようにします。

于 2010-12-24T12:31:09.820 に答える