web-dev-qa-db-ja.com

MySQLラウンドフロートが予想よりもはるかに多いのはなぜですか?

UPDATE some_table SET some_float_field=1919.987 WHERE id=123

SELECT * FROM some_table WHERE id=123

ここで、some_float_fieldは、「float」として定義されたフィールドです(特定のサイズ値はありません)。

結果として期待される値は1919.987です。代わりに、1919.99に丸められます

どうして? 32ビット(単精度)浮動小数点数は、それを正しく格納するのに十分な精度を備えています。

12
matteo

クエリを実行すると:

SELECT * FROM some_table WHERE id = 123

浮動小数点数のフォーマットは、ユーザーインターフェイスに依存しています。使用しているインターフェースは、2文字以上ではなく2文字を使用しています。結局のところ、表示する「正しい」番号に関する情報はありません。

数値を文字列または小数としてフォーマットすることにより、正しい数値を表示するようにインターフェイスを説得できます。例えば:

select format(some_float_field, 3)

これを小数点以下3桁の文字列に変換します。注意:不要なコンマも追加されます。これも機能するはずです:

select cast(some_float_field as decimal(8, 3))

また、トリックを行う必要があります。

次のような操作を行うことで、データが正しいことを簡単に検証できることに注意してください。

select *
from some_table
where some_float_field between 1919.987 - 0.0001 and 1919.987 + 0.0001;

浮動小数点値に=を使用したくないが、すでに理解していることに注意してください。

12
Gordon Linoff

FLOAT のマニュアルから:

FLOATおよびDOUBLEタイプは、おおよその数値データ値を表します。 MySQLは単精度値に4バイトを使用します。

ここでの強調は、近似にあります。 exact値を格納する必要がある場合は、実際には DECIMAL データ型を使用する必要があります。

FLOATの場合、 MySQLはバイナリ浮動小数点演算にIEEE標準754を使用して、数値の任意の部分を4バイト(またはDOUBLEの場合は8)に「圧縮」します

これは、値(小数部と小数)couldに関係なく、任意の値に適用されることに注意してください。 4バイトで正確に表現されます!たとえば、浮動小数点での0.01の表現は、正確に0.009999999776482582092285156250です。ただし、0.01は別のストレージ形式を使用して32ビットのメモリに完全に適合します。

ウィキペディアは浮動小数点の概念をかなりよく説明しています

アルゴリズムは、列定義で指定された精度の影響を受けることに注意してください。
このSQLフィドルの例を参照してください。

10
Kaii