- ベストアンサー
データ型でFloatとreal の計算の違い?
教えてください。 ストアドでfloor(数量(reat) × 単価(money))=金額という計算をさせています。 そこで、200(コ)×9.4(円)=1879円と出るのです。floorで切り捨てても、1880円のはずです。flootなしでやっても、1879,9998と出ます。 何度入力しなおしても同じです。 Floatだと、1880となります。 他の計算はちゃんとできているようです(ざっと見た限りで100%確かめた訳ではありません) 理由がわからないのですが、教えてください。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
floatもrealもいわゆる概数といわれるデータ型で、小数の保持には必ず誤差が生じます。 一方、SQL Serverにはデータ型の優先順位というものがあります。 http://msdn.microsoft.com/ja-jp/library/ms190309.aspx floatもrealもmoneyより上です。 したがって、float * money, real * moneyの演算を行うと、moneyはそれぞれfloat, realに変換されてから演算に使われます。 moneyで9.4と持っていたものがreal型に変換されると、結局9,4にはなりません。 おそらく9.399999389...あたりになってしまいます。realの有効桁数は7桁しかありませんから、小数点以下7桁目以降はアテにならない数字になります。 これに200を掛けても1879.999877..などとなるため、floorを掛けても1879になってしまいます。 floatも基本は同じですが、有効桁数が15桁あります。 moneyの9.4はおそらく9.40000000000004くらいの精度で変換されます。したがってfloorを掛けても1880と出ます。 しかし、誤差が上に出るか、下に出るかは扱う数字により保証の限りではありません。 したがって、real型やfloat型を金額計算に用いるべきではありません。 numeric(decimal)で計算すべきでしょう。 #質問者さんは結果をmoney型で受け取ろうとされているようです。
その他の回答 (2)
- 3rd_001
- ベストアンサー率66% (115/174)
結論がでたようですが、こちらも以下で再現しました。 できれば第三者が再現可能なソースを提示していただけると理解が早いです。 ----------- DECLARE @rReat Real DECLARE @mMoney money DECLARE @fReat float set @rReat =200 set @fReat =200 set @mMoney = 9.4 select @rReat * @mMoney select FLOOR(@rReat * @mMoney) select @fReat * @mMoney select FLOOR(@fReat * @mMoney) ------------- 1880 (1 行処理されました) ---------------------- 1879 (1 行処理されました) ---------------------- 1880 (1 行処理されました) ---------------------- 1880 (1 行処理されました)
お礼
3rd_001 さん、ありがとうございます。 Floorで切り捨てているから、中途半端な数字になるのですよね。 でも通常は1円以下の数字は切り捨てるので、Floorが便利だったのです。 また次回からはソースも提示するようにします。 本当にありがとうございました。
- 3rd_001
- ベストアンサー率66% (115/174)
DECLARE @rReat Real DECLARE @rMoney Real DECLARE @fReat float DECLARE @fMoney float set @rReat =200 set @rMoney =9.4 set @fReat =200 set @fMoney = 9.4 select @rReat * @rMoney select @fReat * @fMoney select 200*9.4 試しに上記で計算してみましたが、すべて「1880」になりました。 再現ケースを示してください。 参考:float 型と real 型 (Transact-SQL) http://msdn.microsoft.com/ja-jp/library/ms173773.aspx
補足
3rd_001 さん、ありがとうございます。 実際に使用しているのは、下記SQLですが、テストで新しいテーブルを作成し、数量をreal型にすると、同じ結果(1879.99988)が出ます。 単価をreat型にしても同じです。 SQLがExpressのせいでしょうか(まさか??) 私のPC,もしくはSQL固有の問題なのでしょうか? 参考リンクも読みましたが、real型で問題あるとは思えません。 begin SELECT TOP (100) PERCENT 発注明細ID, 発注管理ID, 部品ID, 内訳, 数量, 単位, 単価, FLOOR(数量 * 単価) AS 金額, 納品, 摘要, 員数, 員数単位 FROM dbo.T_発注明細 where 発注管理ID=@myid ORDER BY 発注明細ID end
お礼
jamshid6 さん、ありがとうございます。 <小数の保持には必ず誤差が生じます>これは読んでいたのですが、 小数点第何位かをまとめるのだろうと勝手に解釈していました。 データ型で計算が違ってくるとは思ってもいませんでした。 勉強になりました。 数量を decimal(10,2)に変更します。 ありがとうございました。