アクセスログを見ていると、ときどき
http://10395.diarynote.jp/200606080926140000/
がトラップになって 「sql server float floor」や「sql trunc float」で飛んでくる人がいるんで逆突っ込み。
基本的に Microsoft SQL Server とか .NET Framework とかで float を使うべきではない。富豪プログラミング的な理論かもしれないが。
float に関してきちんと警告を出しているところとして、php のサイトがある。
http://jp2.php.net/manual/ja/language.types.float.php
ここに挙がっている例を PostgreSQL に適用して僕が試したのが
http://10395.diarynote.jp/200502170904060000/
に余談レベルで書いているが、検索エンジン様が float絡みのときは引っかけてくれない。
ちゅうわけで、 SQL Server 2008 で実験。
上記の SQL を実行した結果。
同じようなことを C# で。
結果
そういうわけで、通常のビジネスシーン、演算して整数での切り捨てとかが入っているような場合とかは float は利用せず、代わりに十進型(decimal)を利用しましょう。
・・・ただ、Oracle ではこの現象がでませんでした。ずるしてる?w
---
2009年9月14日
サンプルに floor しない場合を追記
2011年2月24日
「Float を主キーにしてはいけません。」も参照。
http://10395.diarynote.jp/201102080112172931/
float型で見かけは同じ数値だけどWHERE句の = でひっかからない例も挙げています。
---
2013年2月7日追記
つまり、「SQL float」「SQL Server float」などの語句で検索しているのが間違いであり、知るべき情報はIEEE754 で決められている「float型」自体についてである。
http://ja.wikipedia.org/wiki/%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%95%B0
---
2013年3月30日追記
ふはははは。俺の時代が来た(違
http://www.oreilly.co.jp/books/9784873115894/#toc
第9章参照
---
2014年1月16日追記
Oracle の 「float 型」はIEEE754 の float型ではなく、
Number型の subtype となっており、
また Oracle には IEEE754 のfloat に対応する「binary_float型」があります。
えぇ、久しぶりに Oracle 触った時にひっかかりました。orz
http://10395.diarynote.jp/200606080926140000/
がトラップになって 「sql server float floor」や「sql trunc float」で飛んでくる人がいるんで逆突っ込み。
基本的に Microsoft SQL Server とか .NET Framework とかで float を使うべきではない。富豪プログラミング的な理論かもしれないが。
float に関してきちんと警告を出しているところとして、php のサイトがある。
http://jp2.php.net/manual/ja/language.types.float.php
ここに挙がっている例を PostgreSQL に適用して僕が試したのが
http://10395.diarynote.jp/200502170904060000/
に余談レベルで書いているが、検索エンジン様が float絡みのときは引っかけてくれない。
ちゅうわけで、 SQL Server 2008 で実験。
SELECT FLOOR((0.1 + 0.7) * 10) AS 普通の結果
SELECT FLOOR((CAST(0.1 AS FLOAT) + CAST(0.7 AS FLOAT)) * 10) AS FLOATで計算
SELECT (CAST(0.1 AS FLOAT) + CAST(0.7 AS FLOAT)) * 10 AS FLOORしない
SELECT FLOOR(CAST(0.8 AS FLOAT) * 10) AS 足し算をしない
上記の SQL を実行した結果。
普通の結果
---------------------------------------
8
(1 行処理されました)
FLOATで計算
----------------------
7
(1 行処理されました)
FLOORしない
----------------------
8
(1 行処理されました)
足し算をしない
----------------------
8
(1 行処理されました)
同じようなことを C# で。
using System;
namespace FloatTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Math.Floor(((decimal)0.1 + (decimal)0.7) * 10));
Console.WriteLine(Math.Floor((0.1F + 0.7F) * 10));
Console.WriteLine(((0.1F + 0.7F) * 10));
Console.WriteLine(Math.Floor((0.1 + 0.7) * 10));
Console.WriteLine(Math.Floor((0.8F) * 10));
}
}
}
結果
8
7
8
7
8
そういうわけで、通常のビジネスシーン、演算して整数での切り捨てとかが入っているような場合とかは float は利用せず、代わりに十進型(decimal)を利用しましょう。
・・・ただ、Oracle ではこの現象がでませんでした。ずるしてる?w
select trunc((cast(0.1 AS binary_float) + cast(0.7 AS binary_float)) * 10)
from dual;
TRUNC((CAST(0.1ASBINARY_FLOAT)+CAST(0.7ASBINARY_FLOAT))*10)
-----------------------------------------------------------
8.0E+000
---
2009年9月14日
サンプルに floor しない場合を追記
2011年2月24日
「Float を主キーにしてはいけません。」も参照。
http://10395.diarynote.jp/201102080112172931/
float型で見かけは同じ数値だけどWHERE句の = でひっかからない例も挙げています。
---
2013年2月7日追記
つまり、「SQL float」「SQL Server float」などの語句で検索しているのが間違いであり、知るべき情報はIEEE754 で決められている「float型」自体についてである。
http://ja.wikipedia.org/wiki/%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%95%B0
---
2013年3月30日追記
ふはははは。俺の時代が来た(違
http://www.oreilly.co.jp/books/9784873115894/#toc
第9章参照
---
2014年1月16日追記
Oracle の 「float 型」はIEEE754 の float型ではなく、
Number型の subtype となっており、
また Oracle には IEEE754 のfloat に対応する「binary_float型」があります。
えぇ、久しぶりに Oracle 触った時にひっかかりました。orz
コメント
つまり1桁4ビットです。4ビットは、2の4乗なので、16通りの組合せを表現できますが、
そのうち10通りを使って1桁の精度を正確に保持しています。
というわけで、"ずる"はしていませんが、"贅沢"にビットを消費することで、
10進数の計算で上記の問題が起こらないようになっています。
一方、ORACLEでも2進数精度であるBINARY_FLOAT形だと、同じことが起こると思います。
NUMBER 型では SQL Server も PostgreSQL も問題起こりません。
「ずるしている?」というのは「きちんと検証はしていないが、BINARY_FLOAT に対する演算は一旦NUMBER型にCastして演算してBINARY_FLOAT型に戻しているように思える」という意味です。「Float型なのに Floatで演算していない~」ってことで「ずるしている」と書きましたが多彩なプラットフォーム(CPU)で動く想定なので妥当な実装だと思います。