Articles

FloatまたはRealデータ型を使用する危険性

浮動小数点演算についての古い冗談があります。

“ケーキを3つにカットすると、各ピースはケーキの0.33です。 私は私にケーキの0.99を与えることを一緒に戻って三つの部分すべてを固執する場合。 ケーキの残りの部分はどこに行ったのですか?”
—”シンプル。 それはナイフで立ち往生している少しです”

浮動小数点演算は、計算のオーバーフローエラーを避けるために近似を許容し、管理することです。 現実の世界では、私たちは通常、数値の精度を気にし、代わりにオーバーフローを避けるためにスペースとリソースを犠牲にします。

科学は誤差の範囲内で幸せに働くのに対し、ビジネス会計では精度が重要です。 私がカブプログラマーだったとき、私はかつて私が株式仲買人の取り引きの利益を計算する完全に適した方法であると思ったものを書いた。 百万ポンドでは、それはせいぜいペニーまたは二つだった。 私はよく喜んでいました。 これは、財務パッケージの開発に当時使用していたPL/1コンパイラに固有の計算を使用しました。 私は彼らに細かく細工されたアプリケーションを示し、彼らはぞっとしました。 百万ポンドのペニーは無謀であるためにhardboiled都市貿易業者にようであった。 彼らはそれを持っていないだろう。 私は正確に正確だったアセンブラコードでバイナリコード10進数(BCD)パッケージを書くことを余儀なくされました。

SQL Promptには、FLOATREALデータ型の使用を警告するコード分析ルール(BP023)があります。

近似数値データ型

浮動小数点演算は、大量の計算を行うための汎用性の高い方法を与えながら、メモリを節約する これは、多くの種類の科学計算、特に浮動小数点演算の倍精度IEEE754標準に準拠する計算にはまだ便利ですが、必然的に妥協点になります。 手がかりは、このタイプのデータと算術の名前にあります:’近似’。 浮動小数点数はすべての実数を正確に表すことはできません。 ただし、保持できる数値の大きさの範囲は、常に正確に保持されていなくても、他の数値型で可能な範囲よりもはるかに大きくなります。

浮動小数点計算の使用から生じる問題は、複雑な計算中の丸め誤差によるものであり、データが”悪い条件”である場合に最もよく見られ、入力の小さな変 不正確さは、数字の表現の精度が高まるにつれてはるかに明らかではありませんが、それでもまだ存在しています。 また、有効であるが浮動小数点で表現できない数値の使用には、tan(π/2)のような難解な制限もありますが、これらは数学者だけを興奮させる可能性があSQL標準には、3つの浮動小数点、近似データ型、REALDOUBLEPRECISIONFLOAT(n) SQL Serverはこれに準拠していますが、DOUBLEPRECISIONFLOAT(53)FLOAT(24)FLOAT(53)データ型は、IEEE754標準のBinary32(Single)およびBinary64(double)に対応し、4および8バイトで格納され、7および16 これらは、IEEE754も使用する.NET frameworkを使用するアプリケーションと同じ結果を計算することが重要な場合に便利です。 倍精度型は、数値がDECIMALWHERE句など、等価性のテストでは、近似数値を確実に使用することはできません。実際のデータ型(単精度)を使用した計算

私はREALFLOAT(24)データ型、またはそれ以下は、同じように反応します。 SQL Serverで浮動小数点数を試してみるときに最初に覚えておくべきことは、SSMSが浮動小数点数を小さな違いを隠す方法でレンダリングすることです。 たとえば、次のようにします。

1
SELECT Convert(REAL,0.100000001490116119384765625)

…は0.1を与えます

浮動小数点数に格納されている値をより正確に確認するには、str()関数を使用して、実際に必要な精度を指定

1
2
3
4
5
/*10進数0.1は表現できないため、ここでは少し不公平です。
/*10進数0.1は表現できないため、
///////////////////////////////////////////////////浮動小数点;正確なバイナリ表現は、”1100″シーケンスを持ちます
無限に続きます:*/
declare@firstapproximate real=0.1
select str(@firstapproximate,20,16)-0でなければなりません。100000001490116119384765625

すでに、これは驚くべきことです。 結局のところ、私たちは何百万もの行を持つデータを扱っているので、”銀行の丸め”のように平均しない限り、小さなエラーが積み重なります。 そのエラーは、すでに私が紹介で言及した”百万ポンドのペニー”(1/240000000)に近いです!

0.1を避けて浮動小数点のフリークにしましょう。 1を3で割ってみてはいかがでしょうか。 確かにこれは問題ではありませんでしたか?

1
2
3
4
5
を記載@縮リアル=1

となっています。div>を記載@divisorリアル=3

を選択しStr(@縮/@divisor,20,16)として商
–生0.3333333432674408
–すべき0.3333333333333333

てへ。 それはそれが間違ってしまった。 OK、それは小さなエラーですが、銀行家についての私の話を覚えています。 答えは正しいか間違っている、灰色のスーツの男性のための灰色の色合いはありません。 ビジネススクールでは、ダニと十字架だけがあります。 “十分に近い”という意味の兆候はありません。簡単なテストは、1から20までの数で1を除算することです。

何が間違って行くことができますか?

浮動小数点計算と数値計算の結果を格納し、両方を文字列に変換してから文字列を比較することができます(STR()は、複雑になる先頭のス

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

DECLARE @divisor REAL, @dividend REAL = 1
DECLARE @FloatingPointCalculations TABLE (Divisor INT, QuotientFloatingPoint VARCHAR(20), QuotientNumeric VARCHAR(20));
DECLARE @ii INT = 1;
DECLARE @iiMax INT = 20;
WHILE (@ii <= @iiMax)
BEGIN
SELECT @divisor = @ii;
INSERT INTO @FloatingPointCalculations (Divisor, QuotientFloatingPoint,
QuotientNumeric)
SELECT @ii AS divisor, Str(@Dividend / @divisor, 20, 16) AS QuotientFloatingPoint,
Convert(VARCHAR(20), 1.0000000 / @ii) AS QuotientNumeric;
SELECT @ii += 1;
END;
SELECT The.Divisor, The.QuotientFloatingPoint, The.QuotientNumeric
FROM @FloatingPointCalculations AS The;

Now, what if we list the rows where the numbers don’t match?

1
2
3

SELECT The.Divisor, The.QuotientFloatingPoint, The.QuotientNumeric
FROM @FloatingPointCalculations The
WHERE Left(LTrim(The.QuotientFloatingPoint),16)<> Left(LTrim(The.16)

うわ! 除数が1、2、4、8、または16であった場合にのみ、正しい結果が得られました。何らかの形で浮動小数点数が正確で、数値バージョンが正確でないことを望んでいる場合は、Excelで計算された数値商を次に示します。

:

FLOAT(25)以上(倍精度)を使用した計算

倍精度浮動小数点を使用する場合、FLOAT(25)STR()関数は、小数点。 16を超える場合、結果は切り捨てられます。 倍精度データ型には16桁の数字があり、単精度データ型には7桁の数字があります。 また、単精度データ型が最初の7桁の数字を正しく取得することもわかります。 同様に、倍精度は最初の16桁を右に取得します。 近似を見るために数を広げることができます。1

2
宣言@FirstApproximate FLOAT(53)=100000000000000000.1
Select Str(@FirstApproximate,40,16)BignumberWithAdecimalとして

その小数部分は消えましたか? それはおそらくほんのわずかな違いですが、いくつかの計算では、問題を引き起こす可能性があります。

結論

浮動小数点演算は、ストレージ上で高速で経済的ですが、おおよその結果を提供します。 それはよく調節された科学的な適用のためにない数が”右”または”間違っている”であることを要求する財政の計算のために適している。 また、2つの近似数値の等価性を確実かつ一貫してテストすることができないため、データベースには余分な欠点があります。SQLデータ型や算術演算で浮動小数点数を使用しないでください。 おおよその型は、目的のためにSQL標準にあります。 私は今日、適切な要件があるsql Serverの倍精度浮動小数点データ型に常に固執しています。 気象システムのモデル化や軌道のプロットなどの目的には最適ですが、平均的な組織がデータベースを使用する可能性のある計算の種類には最適でこれらの型の誤った使用を発見した場合は、代わりに適切なDECIMALNUMERIC型に切り替える必要があります。 浮動小数点演算が必要で、その理由を説明できることがわかっている場合は、28人の死亡に直接つながった有名なPatriotミサイルの失敗で発生したような浮動小数点の落とし穴を避けるのに十分なことを知っているでしょう。