floatデータ型とdecimalデータ型の違い


175

MySQLでfloatおよびdecimalデータ型を使用すると、どのような違いがありますか?

どちらを使用すればよいですか?


を使用しないでくださいFLOAT(m,n)。2つの丸めが発生します。その間、それは何の役にも立ちません。
リックジェームズ

回答:


185

これは私がこの疑問を抱いたときに私が見つけたものです。

mysql> create table numbers (a decimal(10,2), b float);
mysql> insert into numbers values (100, 100);
mysql> select @a := (a/3), @b := (b/3), @a * 3, @b * 3 from numbers \G
*************************** 1. row ***************************
  @a := (a/3): 33.333333333
  @b := (b/3): 33.333333333333
@a + @a + @a: 99.999999999000000000000000000000
@b + @b + @b: 100

小数は、この場合に行うべきことを正確に実行し、残りを切り捨てて、1/3の部分を失いました。

したがって、合計の場合は小数の方が適していますが、除算の場合はフロートのほうが適切です。つまり、DECIMALを使用しても、「失敗を証明する算術演算」は決して得られません。

お役に立てれば。


4
優れたテスト。数年前、C libのデータ変換関数は、ASCIIから浮動小数点に変換された値に、たとえばSQLServerの値と比較すると、多くの微小な違いをもたらすことがよくありました。これはめったに本当ではありません。トレードオフが何であるかを確実に知ることが最善であるため、テストは最良のポリシーです。

15
実際、DECIMALオプションは誤っています。33.333333333を3回追加すると、100は得られません。100を3で割ると、後続の桁のセットが繰り返されない限り、有理数が得られないため、3を掛けて100を得ることができません。電卓とそれを試してみてください。論理的には、1/3 + 1/3 + 1/3は3/3のIE:1に等しいはずですが、この有理数のクラスではこれを行うことができません。浮動小数点数の答えは正しいですが、会計士はそれを嫌います!
user2548100 2013

5
@a99.999999999000000000000000000000に10進数を与えていませんか?技術的に正しいです。
Vincent Poirier

78

ほとんどの環境の「フロート」は、2進浮動小数点型です。(特定のポイントまでの)base-2値を正確に格納できますが、base-10(10進数)値の多くを正確に格納できません。フロートは科学計算に最も適しています。それらはほとんどのビジネス指向の数学に適切ではなく、浮動小数点数の不適切な使用はあなたを噛みます。多くの10進値は、基数2で正確に表すことができません。0.1たとえばできません1.0 - 0.1 = 0.8999999。そのため、のような奇妙な結果が表示されます。

小数は10進数を格納します。Decimalはほとんどのビジネス数学に適したタイプです(ただし、組み込みの「金銭」タイプは財務計算に適しています)。この場合、値の範囲は整数タイプによって提供される範囲を超え、小数値が必要です。小数は、その名前が示すように、10を底とする数値用に設計されています。小数の値を(ここでも、特定の点まで)正確に格納できます。


@Michael Petrotta-ユーザーはフォームで与えられたフィールドに自分の10進数を入力するだけです。DBに保存するだけです。より適しています。?
ハッカー

12
@Pradeep:私の質問には答えていないと思います。それは自分で答えがわからないためかもしれません-マネージャーや顧客に詳細を尋ねるのに抵抗があるかもしれません。その場合は、弾丸をかじり、数時間一緒に座って、実際にアプリケーションをウォークスルーすることをお勧めします。正確に、そして詳細に、あなたのデータは何使用されていますか?
Michael Petrotta

1
実際、現在、floatとDECIMALはどちらも同じ方法で数値を格納しています。違いは、それらの数値の使用方法にあります。DECIMALはすべてのビットを使用して、暗黙の小数点を含む2の補数の整数を構成します。floatには2つの整数があり、一方はもう一方を累乗します。基数と指数はどちらも2の補数の整数です。
user2548100 2013

1
あなたの答えは技術的に正しいかもしれませんが、floatがバイナリ型であることを強調すると、両方が同じ形式でデータを格納するという意味がわかりにくくなります。1乗した浮動小数点数は整数であり、そのとおりに格納されます。実際、80ビット精度の浮動小数点数の場合、ベースはint64です。逆に、整数を累乗するライブラリを作成した場合、整数、DECIMALS、ローマ数字、またはロリポップで同じ問題が発生します。「丸め誤差」を引き起こしているのはストレージではなく、ライブラリが数学を処理するためのものです。
user2548100 2013

1
質問の質が非常に低く、問題のOP領域が何であるかを示すパラメーターが実質的に与えられていないため、適切な応答が何かを知ることは困難です。一般に、DECIMALはより多くの数を格納し、数学ライブラリは会計士の期待に応えますが、ダブルフロートは、数学ライブラリを大幅に最適化した非効率的なストレージメディアです。
user2548100 2013

21

MySQLは最近、DECIMAL型を格納する方法を変更しました。過去には、ASCII(またはニブル)の数値表現(2の補数の整数またはその派生物)を構成する各桁の文字(またはニブル)を格納していました。

DECIMALの現在のストレージ形式は、一連の1、2、3、または4バイトの整数で、そのビットが連結されて暗黙の小数点を持つ2の補数を作成し、ユーザーが定義し、宣言時にDBスキーマに格納されます。列を指定して、10進数のサイズと小数点位置を指定します。

例として、32ビットのintを取得する場合、0〜4,294,967,295の任意の数を格納できます。それは確実に999,999,999をカバーするだけなので、2ビットをスローして使用した場合(1 << 30 -1)、何も諦めません。4バイトだけですべての9桁の数字をカバーする方が、4つのASCII文字または8ニブルの数字を使用して32ビットで4桁をカバーするよりも効率的です。(ニブルは4ビットであり、0から15までの値を許可しますが、0から9に必要な値よりも多くなりますが、3に移動しても無駄をなくすことはできません。これは0から7の値しかカバーしないためです)

MySQLオンラインドキュメントで使用されている例では、例としてDECIMAL(18,9)を使用しています。これは、暗黙の小数点の前に9桁、後ろに9桁あります。これは、上記で説明したように、次のストレージを必要とします。

18 8ビット文字として:144ビット

18 4ビットニブルとして:72ビット

2つの32ビット整数として:64ビット

現在、DECIMALは最大65桁をサポートしています。DECIMAL(M、D)の場合、Mの最大値は65で、Dの最大値は30です。

一度に9桁のチャンクを必要としないように、32ビットより小さい整数を使用して、1、2、および3バイトの整数を使用して桁を追加します。なんらかの理由で、論理を否定するために、署名されていない整数ではなく、署名された整数が使用されたため、1ビットがスローされ、次のストレージ機能が発生しました。1、2、4バイトの整数の場合、失われたビットは問題ではありませんが、3バイトの整数の場合は、その1ビットが失われたために桁全体が失われるため、災害です。

7ビット整数の場合:0-99

15ビット整数の場合:0〜9,999

23ビット整数の場合:0〜999,999(24ビット整数の場合は0〜9,999,999)

1、2、3、および4バイトの整数が連結されて「ビットプール」を形成します。DECIMALは、数値を2の補数の整数として正確に表すために使用します。小数点は格納されません、それは暗示されます。

これは、「数値」をCPUが数値として認識するものに変換するために、DBエンジンがASCIIからintに変換する必要がないことを意味します。丸めなし、変換エラーなし、これはCPUが操作できる実数です。

この種類の数値に対するハードウェアサポートがないため、この任意の大きな整数の計算はソフトウェアで行う必要がありますが、これらのライブラリは非常に古く、高度に最適化されており、IBM 370 Fortran任意精度浮動小数点データをサポートするために50年前に記述されています。 。これらは、CPU整数ハードウェアで行われる固定サイズの整数代数や、FPUで行われる浮動小数点計算よりもはるかに低速です。

ストレージ効率の点では、フロートの指数はすべてのフロートに付加され、小数点の位置を暗黙的に指定するため、非常に冗長であり、DBの作業には非効率的です。DBでは、小数点の前の位置がわかっているため、DECIMAL列の値を持つテーブル内のすべての行は、その小数点が配置され、格納される場所の1&onlyの指定を確認するだけで済みます。スキーマでは、MおよびDの値の意味として、DECIMAL(M、D)の引数として使用されます。

さまざまな種類のアプリケーションにどの形式を使用するかについて、ここで見つかった多くの注釈は正しいので、私は要点を説明しません。リンクされたMySQLオンラインドキュメントを管理している人は誰も上記のことを理解していないため、ここでこれを書くのに時間をかけました。彼らが書いている内容をどれほどよく理解していないかを示す良い目安は、主題が非常に混乱し、ほとんど解読できない表現です。

最後に、高精度の浮動小数点計算が必要な場合は、過去20年間で浮動小数点コードが大幅に進歩しており、96ビットおよび4倍精度浮動小数点のハードウェアサポートがすぐ近くにあります。しかし、格納された値の操作が重要な場合、そこには適切な任意精度のライブラリがあります。


IntelのHazwellアーキテクチャーでは、256桁の整数でAVX-2演算があり、77桁が表す可能性のあるすべての値をカバーし、DECIMALの拡張精度整数を直接演算するために使用できると思います。Oracleが77桁対65桁をカバーする将来の新しい形式のDECIMALをサポートすることは賢明であると思われるかもしれません。ソフトウェアではなくハードウェアを使用すると、パフォーマンスが5〜10倍向上すると推定します。2 ^ 256 = 115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129、639,936(78桁)

Intelのベクトルプロセッサが512ビットの数学演算をサポートするようになりました。これは154桁をカバーします。2 ^ 512 = 13,407,807,929,942,597,099,574,024,998,205,846,127,479,365,820,592,393,377,723,561,443,721,764,030,073,546,976,801,874,298,166,903,427,690,031,858,186,486,050,853,753,882,811,946,569,946,433,649,006,084,096(155桁)

13

MySQLだけでなく、float型とdecimal型の違いは、小数値を表す方法です。浮動小数点型は、2進数で分数を表します{m*2^n | m, n Integers}。これは、値をとしてのみ表すことができます。1/5などの値は正確に表現できません(丸め誤差なし)。10進数も同様に制限されますが、などの数値を表します{m*10^n | m, n Integers}。小数はまだ1/3のような数値を表すことはできませんが、金融などの多くの一般的なフィールドでは、特定の小数部分が常に忠実度を失うことなく表現できることが期待されることがよくあります。10進数は$0.20(1ドルの5分の1)のような値を表すことができるため、このような状況ではこれが推奨されます。


Intelプロセッサはすべての中間のdouble float演算を80ビット精度で実行するため、最終結果が80ビットから64ビットにトリミングされても、丸め誤差はほとんど例外なく発生します。多くの浮動小数点ソフトウェアライブラリでさえ、これらおよび他の何百もの算術異常を処理できます。したがって、理論と実践は、この分野では大きく異なります。

9

小数は、特定の小数位が必要なマネーなどの固定数量用です。フロートは...浮動小数点精度の数値を格納するためのものです。



5
mysql> CREATE TABLE num(id int ,fl float,dc dec(5,2));
Query OK, 0 rows affected (0.00 sec)


mysql> INSERT INTO num VALUES(1,13.75,13.75);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO num VALUES(2,13.15,13.15);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM num WHERE fl = 13.15;
Empty set (0.00 sec)

mysql> SELECT * FROM num WHERE dc = 13.15;
+------+-------+-------+
| id   | fl    | dc    |
+------+-------+-------+
|    2 | 13.15 | 13.15 |
+------+-------+-------+
1 row in set (0.00 sec)

mysql> SELECT SUM(fl) ,SUM(dc)  FROM num;
+--------------------+---------+
| SUM(fl)            | SUM(dc) |
+--------------------+---------+
| 26.899999618530273 |   26.90 |
+--------------------+---------+
1 row in set (0.00 sec)


mysql> SELECT * FROM num WHERE ABS(fl -  13.15)<0.01;
+------+-------+-------+
| id   | fl    | dc    |
+------+-------+-------+
|    2 | 13.15 | 13.15 |
+------+-------+-------+
1 row in set (0.00 sec)

2

パフォーマンスよりも精度が悪い場合は、浮動小数点を使用した計算が小数よりもはるかに高速であることに注意してください。


2

浮動小数点型(概算値)-FLOAT、DOUBLE

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

FLOATの場合、SQL標準では、括弧で囲まれたキーワードFLOATに続くビット単位の精度(指数の範囲ではない)をオプションで指定できます。MySQLはこのオプションの精度指定もサポートしていますが、精度値はストレージサイズを決定するためにのみ使用されます。精度が0〜23の場合は、4バイトの単精度FLOAT列になります。24から53の精度は、8バイトの倍精度DOUBLE列になります。

MySQLは非標準の構文を許可します:FLOAT(M、D)またはREAL(M、D)またはDOUBLE PRECISION(M、D)。ここで、「(M、D)」とは、合計で最大M桁まで値を格納できることを意味します。このうち、D桁は小数点以下の場合もあります。たとえば、FLOAT(7,4)として定義された列は、表示されると-999.9999のようになります。MySQLは値を格納するときに丸めを実行するため、FLOAT(7,4)カラムに999.00009を挿入すると、おおよその結果は999.0001になります。

浮動小数点値は概算であり、正確な値として格納されていないため、比較でそれらを正確なものとして処理しようとすると、問題が発生する可能性があります。また、プラットフォームまたは実装の依存関係の影響を受けます。

移植性を最大にするために、近似数値データ値の格納を必要とするコードでは、精度や桁数を指定せずにFLOATまたはDOUBLE PRECISIONを使用する必要があります。

https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html

浮動小数点値の問題

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

次の例では、DOUBLEを使用して、浮動小数点演算を使用して実行される計算が浮動小数点エラーの影響を受ける方法を示します。

mysql> CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql> INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
    -> (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
    -> (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
    -> (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
    -> (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
    -> (6, 0.00, 0.00), (6, -51.40, 0.00);

mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b
    -> FROM t1 GROUP BY i HAVING a <> b;

+------+-------+------+
| i    | a     | b    |
+------+-------+------+
|    1 |  21.4 | 21.4 |
|    2 |  76.8 | 76.8 |
|    3 |   7.4 |  7.4 |
|    4 |  15.4 | 15.4 |
|    5 |   7.2 |  7.2 |
|    6 | -51.4 |    0 |
+------+-------+------+

結果は正しいです。最初の5つのレコードは比較を満たしてはいけないように見えます(aとbの値は異なっているように見えません)が、係数によっては、数値間の差異が10進数の10程度前後に現れるため、そうする場合があります。コンピュータアーキテクチャ、コンパイラのバージョン、最適化レベルなど。たとえば、CPUによって浮動小数点数の評価が異なる場合があります。

列d1およびd2がDOUBLEではなくDECIMALとして定義されていた場合、SELECTクエリの結果には1行のみが含まれます(最後の行は上に表示されています)。

浮動小数点数の比較を行う正しい方法は、最初に数値間の差異の許容範囲を決定し、次に許容値との比較を行うことです。たとえば、浮動小数点数が1万分の1の精度(0.0001)内で同じであれば浮動小数点数は同じであると見なすことに同意した場合、許容値より大きい差を見つけるために比較を記述する必要があります。

mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
    -> GROUP BY i HAVING ABS(a - b) > 0.0001;
+------+-------+------+
| i    | a     | b    |
+------+-------+------+
|    6 | -51.4 |    0 |
+------+-------+------+
1 row in set (0.00 sec)

逆に、数値が同じである行を取得するには、テストで許容値内の違いを見つける必要があります。

mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
    -> GROUP BY i HAVING ABS(a - b) <= 0.0001;
+------+------+------+
| i    | a    | b    |
+------+------+------+
|    1 | 21.4 | 21.4 |
|    2 | 76.8 | 76.8 |
|    3 |  7.4 |  7.4 |
|    4 | 15.4 | 15.4 |
|    5 |  7.2 |  7.2 |
+------+------+------+
5 rows in set (0.03 sec)

浮動小数点値は、プラットフォームまたは実装の依存関係の影響を受けます。次のステートメントを実行するとします。

CREATE TABLE t1(c1 FLOAT(53,0), c2 FLOAT(53,0));
INSERT INTO t1 VALUES('1e+52','-1e+52');
SELECT * FROM t1;

一部のプラットフォームでは、SELECTステートメントはinfおよび-infを返します。その他の場合、0と-0を返します。

上記の問題の意味するところは、マスターでmysqldumpを使用してテーブルの内容をダンプし、ダンプファイルをスレーブにリロードしてレプリケーションスレーブを作成しようとすると、2つのホスト間で浮動小数点列を含むテーブルが異なる可能性があります。

https://dev.mysql.com/doc/refman/5.5/en/problems-with-float.html


0

ハード&ファストルール

保存する数値を加算、減算、または乗算するだけでよい場合は、DECIMALが最適です。

データを除算したり、他の形式の算術や代数を実行したりする必要がある場合は、ほぼ確実にfloatを使用すると便利です。浮動小数点ライブラリ、およびIntelプロセッサでは、浮動小数点プロセッサ自体に、典型的な数学関数、特に超越関数を実行するときに発生する例外のブリザードを修正、修正、検出、処理するためのTONの操作があります。

精度については、3,600以上の予算単位について、その単位の連結ノードに対する月ごとの3,000以上のアカウントのそれぞれの貢献率を計算し、次にそのパーセンテージのマトリックス(3,000 + x 12 x 3,600)に基づいて予算システムを作成しました。最上位の組織ノードの予算額を組織ノードの次の3つのレベルに掛けて、そこから3,200の詳細単位すべてのすべての(3,000 + 12)値を計算しました。何百万、何百万、何百万もの倍精度浮動小数点計算。いずれの計算でも、ボトムアップ統合におけるこれらすべての予測のロールアップが組織の最高レベルに戻されます。

これらの計算をすべて行った後の合計浮動小数点誤差はゼロでした。それは1986年のことでしたが、今日の浮動小数点ライブラリは、当時よりはるかに優れています。インテルは、80ビット精度の倍精度の中間計算をすべて実行します。これにより、丸め誤差がほとんどなくなります。誰かが「それは浮動小数点エラーです」と言ったとき、それはほとんど確実ではありません。


-2

float(およびdouble)は2進分数を表します

decimal 小数を表します


-2
declare @float as float(10)
declare @Decimal as decimal(10)
declare @Inetger as int

set @float =10.7
set @Decimal =10.7
set @Inetger=@Decimal

print @Inetger

値を整数印刷10に設定すると浮動小数点で、10進数では11

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.