6

私は本当に奇妙な¿バグに直面していますか? 今mysql+phpで。単純な選択です。次の例では、複数のフィールドを使用して問題を説明しています。

  • 「フィールド」は11.5
  • $phpvar は 1.15 です

MySQL クエリ:

select round(field * " . $phpvar . " ,2) as a1, 
       round(field * 1.15 ,2) as a2, 
       round(11.5 * " . $phpvar . " ,2) as a3, 
       round(11.5 * 1.15 ,2) as a4, 
       field * " . $phpvar . " as a5 
from ...

わかりました、13.23 を取得しようとしています。"field" * $phpvar = 13.225ですから、 round(13.225,2) を使用すると、13.23 になるはずですよね? はい、いいえ。

クエリ結果:

  • a1 [round(field * " . $phpvar . " ,2)] => 13.22
  • a2 [ラウンド (フィールド * 1.15 ,2)] => 13.22
  • a3 [round(11.5 * ". $phpvar . " ,2)] => 13.23
  • a4 [丸め (11.5 * 1.15 ,2)] => 13.23
  • a5 [field * " . $phpvar . "] => 13.225 (丸めなし)

私は何が欠けていますか?「フィールド」を使用すると、結果が偽のラウンドになる可能性はありますか?

4

2 に答える 2

9

問題は、DOUBLE 値と FLOAT 値の格納方法です。

11.5 や 22.475 のような値が 11.499999999999~ や 22.47500000000000001 のような近似値に格納される可能性があり (おそらく)、一部の計算や丸めによって誤った結果が生じる可能性があります。

float 値をDECIMAL coulmn 型に格納することを常にお勧めします。この場合、値はすべての 10 進数で正確に格納され、概算はされません。

于 2012-05-04T10:20:36.697 に答える
5

正確な数値リテラル (1.15例の 4 つすべてと11.5後者の 2 つのなど) は、MySQL の型を使用してエンコードされます。DECIMAL

field最初の 2 つの例では、 (型のDOUBLE) をそのようなリテラルで乗算した結果は別のものであり、 8 バイトのIEEE 標準浮動小数点表現 (つまり、 binary64DOUBLE )を使用して格納されます。ただし、この表現で は としてエンコードされ、そのビットは次を意味します。 13.2250x402A733333333333

サイン           :0b0

偏った指数: 0b10000000010
               = 1026 (表現には +1023 のバイアスが含まれているため、exp = 3)

    仮数 : 0b[1.] 1010011100110011001100110011001100110011001100110011
               = [1.]6531249999999999555910790149937383830547332763671875
                    ^ バイナリ表現で格納されていない隠しビット

これは次のようになります。

  (-1)^ 0 * 1.6531249999999999555910790149937383830547332763671875 * 2^ 3 
=          13.224999999999996447286321199499070644378662109375000

したがって、この結果を小数点以下 2 桁に四捨五入すると、13.22notが得られ13.23ます。

DECIMAL後者の 2 つの例で使用されている 2 つのリテラルなど、2つの型で乗算を実行すると、別の結果になりDECIMALます。この表現では、 2 進化 10 進形式で正確な精度で13.225エンコードされるため、丸め操作は期待どおりの結果になります。13.23

MySQLマニュアルに記載されているように:

浮動小数点数は近似値であり、正確な値として格納されないため、混乱を招くことがあります。SQL ステートメントに記述された浮動小数点値は、内部で表される値と同じではない場合があります。比較で浮動小数点値を正確なものとして処理しようとすると、問題が発生する可能性があります。また、プラットフォームまたは実装の依存関係にも左右されます。FLOATおよびDOUBLEデータ型は、これらの問題の影響を受けます。列の場合DECIMAL、MySQL は 65 桁の精度で操作を実行します。これにより、最も一般的な不正確さの問題が解決されます。

正確な精度を求めている場合はDECIMAL、要件により適している可能性があります。の範囲/パフォーマンスが必要であるDOUBLEが、望ましい丸め結果を得たい場合は、丸めの前にCONVERT乗算の結果を得ることができますDECIMAL

于 2012-05-04T11:20:15.590 に答える