0

私はSQLを持っています:

SELECT Sum(Field1), Sum(Field2), Sum(Field1)+Sum(Field2)
FROM Table
GROUP BY DateField
HAVING Sum(Field1)+Sum(Field2)<>0;

問題は、field1 と field2 の合計が 9.5-10.3 のような値で、結果が -0,800000000000001 になることがあります。なぜこれが起こるのか、そしてそれを解決する方法を誰か説明できますか?

4

3 に答える 3

2

問題は、field1 と field2 の合計が 9.5-10.3 のような値で、結果が -0.800000000000001 になることがあります。なぜこれが起こるのか、そしてそれを解決する方法を誰か説明できますか?

なぜこれが起こるのか

float型と型はdouble、数値を基数 10 ではなく基数 2 で格納します。数値は、有限のビット数で正確に表現できる場合があります。

9.5 → 1001.1

また、できない場合もあります。

10.3 → 1010.0 1001 1001 1001 1001 1001 1001 1001 1001...

後者の場合、数値は次のように表現できる最も近い値に丸められますdouble

1010.0100110011001100110011001100110011001100110011010 base 2
= 10.300000000000000710542735760100185871124267578125 base 10

減算が 2 進数で行われると、次のようになります。

-0.11001100110011001100110011001100110011001100110100000
= -0.800000000000000710542735760100185871124267578125

通常、出力ルーチンはほとんどの「ノイズ」桁を隠します。

  • Python 3.1 では丸められます。-0.8000000000000007
  • SQLite 3.6 では に丸められ-0.800000000000001ます。
  • printf %gに丸め-0.8ます。

double値が -0.8 と表示されるシステムでも、-0.8 の最適な近似値とは異なることに注意してください。

- 0.11001100110011001100110011001100110011001100110011010
= -0.8000000000000000444089209850062616169452667236328125

したがって、 を使用するプログラミング言語doubleでは、式9.5 - 10.3 == -0.8は false になります。

decimal解決策

このような質問に対する最も一般的な答えは、「10 進演算を使用する」です。この特定の例では、実際により良い出力が得られます。Python のdecimal.Decimalクラスを使用する:

>>> Decimal('9.5') - Decimal('10.3')
Decimal('-0.8')

ただし、まだ対処する必要があります

>>> Decimal(1) / 3 * 3
Decimal('0.9999999999999999999999999999')
>>> Decimal(2).sqrt() ** 2
Decimal('1.999999999999999999999999999')

これらは、2 進数の丸め誤差よりもよく知られている丸め誤差かもしれませんが、重要性が低くなるわけではありません。

実際、次の組み合わせにより、2 進数の分数は同じビット数の 10 進数よりも正確です。

また、専用のハードウェアを備えているため、(PC 上で)はるかに高速です。

ベース 10 について特別なことは何もありません。これは、私たちが持っている指の数に基づいた恣意的な選択です。

生まれたばかりの赤ちゃんの体重が 0x7.5 ポンド (より一般的な用語では、7 ポンド 5 オンス) であると言うのは、体重が 7.3 ポンドであると言うのと同じくらい正確です.許容範囲内です。) 一般に、10 進数は、物理的な測定値を表すのに何の利点もありません。

お金が違う

一定レベルの精度で測定される物理量とは異なり、お金は数えられるため、正確な量になります。奇妙な点は、他のほとんどの離散量のように 1 の倍数ではなく、0.01 の倍数でカウントされることです。

「10.3」が実際に $10.30 を意味する場合は、値を正確に表すために 10 進数タイプを使用する必要があります。

(16 分の 1 ドルだった時代の過去の株価を扱っている場合を除きます。その場合はバイナリで十分です ;-) )

それ以外の場合は、単なる表示の問題です。

有効数字15桁まで正解でした。それはすべての実用的な目的で正しいです。「ノイズ」を隠したいだけの場合は、SQLROUND関数を使用してください。

于 2010-09-21T04:28:40.867 に答える
1

これはおそらく浮動小数点数の実装の影響です。数値を正確に表すことができない場合や、同じ理由で演算の結果が予想と若干異なる場合があります。

修正は、値に丸め関数を使用して不要な数字を切り捨てることです。このように (私は小数点以下の有効桁数を 4 桁に丸めただけですが、もちろん、データに適した精度を使用する必要があります):

SELECT Sum(Field1), Sum(Field2), Round(Sum(Field1)+Sum(Field2), 4)
FROM Table
GROUP BY DateField
HAVING Round(Sum(Field1)+Sum(Field2), 4)<>0;
于 2010-09-12T05:11:49.850 に答える
1

float データ型 (MS Access では Double または Single とも呼ばれる) が不正確であるためだと確信しています。10 のべき乗でスケーリングされた単純な値である 10 進数とは異なります。私の記憶が正しければ、float 値には異なる分母が含まれている可能性があります。つまり、常に基数 10 に正確に変換されるとは限りません。

解決策は、Field1 と Field2 を float/single/double から decimal または currency に変更することです。0.0001 や 0.9999 など、必要な最小値と最大値を含め、保存する必要がある最小値と最大値の例を挙げていただければ、より適切なアドバイスができる可能性があります。

2007 より前のバージョンの Access では、10 進数値の ORDER BY で問題が発生する可能性があることに注意してください。この投稿のコメントを読んで、これに関するより多くの視点を確認してください。多くの場合、これは問題になりませんが、場合によっては問題になる可能性があります。

一般に、float は、極端に小さいか大きい (10 進数が保持できるよりも小さいか大きい) 値になる可能性がある値に使用する必要があります。float は、ある程度の精度を犠牲にしてより正確なスケールを維持することを理解する必要があります。つまり、小数はオーバーフローまたはアンダーフローしますが、フロートはそのまま続行できます。ただし、浮動小数点数の有効桁数は限られていますが、小数の桁はすべて有効です。

列の型を変更できない場合は、当面の間、最終的な計算を丸めることで問題を回避できます。可能な限り最後の瞬間まで丸めないでください。

アップデート

10 進数を使用するという私の推奨事項に対する批判は平準化されており、予期しない ORDER BY の結果についてのポイントではありませんが、浮動小数点数は同じビット数で全体的により正確です。

この事実に異議はありません。しかし、実際にはカウントされているか、10 進法で表現されることが期待される値を扱う方が一般的だと思います。浮動小数点データ型の何が問題なのかという質問をフォーラムで何度も目にしますが、10 進数に関する同じ質問は見当たりません。つまり、人々は小数から始めるべきであり、小数をいつどのように使用するかという飛躍の準備ができたら、小数について学習し、有能になったときに使用を開始できるということです。

それまでの間、小数がそれほど正確ではないことを知っているのに、常に小数を推奨する人がいるのは少しイライラするかもしれませんが、精度がわずかに低下する代わりに、より身近な丸め誤差が発生する現実の世界から離れてはいけません。価値があります。

私の批判者に、その例を指摘させてください

Decimal(1) / 3 * 3降伏1.999999999999999999999999999

よく知られている言葉で言えば、「すべての実用的な目的で正しい」「27 桁まで正しい」ということです。

したがって、実質的に同じことを行う 2 つの方法があり、どちらもばかげた有効桁数まで非常に正確に数値を表すことができ、両方とも丸めを必要としますが、そのうちの 1 つ、他の、より馴染みのあるものを推奨することは決して悪いことではありません。a - a実行できて答えが得られないシステムを初心者が作成するにはどうすればよい0でしょうか? 彼は混乱し、それを理解しようとしている間に仕事を止められるでしょう。それから彼はメッセージボードで助けを求めに行き、「小数を使用してください」と答えます。そうすれば彼は元気になるそれからさらに 5 年間、ある日好奇心を持てるようになるまで成長し、最終的にフロートが何をしているのかを研究し、実際に把握して適切に使用できるようになるまで。

とはいえ、最終的な分析では、小数を推奨することで私を非難することは、宇宙空間では少しずれているように思われると言わざるを得ません.

最後に、次のステートメントは一般化しすぎているため、厳密には正しくないことを指摘しておきます。

float 型と double 型は、基数 10 ではなく基数 2 で数値を格納します。

正確に言うと、最新のシステムのほとんどは、基数が 2 の浮動小数点データ型を格納しています。しかし、すべてではありません。基数 10 を使用する、または使用したことがあります。私が知っている限りでは、eに近い基数 3 を使用するシステムがあり、したがって基数 2 表現よりも最適な基数経済を持っています (あたかもすべてのコンピューター ユーザーの 99.999% にとって本当に重要であるかのように) )。さらに、double は float ですが、float は double ではないため、「float および double 型」と言うと少し誤解を招く可能性があります。Float は float の略ですが、SingleDoubleは float(ing point)サブタイプであり、使用可能な合計精度を意味します。また、Single-Extended および Double-Extended 浮動小数点データ型もあります。

于 2010-09-12T05:12:23.453 に答える