精密計算
TiDB の精度数学サポートは MySQL と一貫しています。詳細については、 MySQL の精密計算を参照してください。
数値型
正確な値の演算の精度計算の範囲には、正確な値のデータ型 (整数および DECIMAL 型) と正確な値の数値リテラルが含まれます。近似値のデータ型と数値リテラルは浮動小数点数として扱われます。
正確な値の数値リテラルには、整数部分または小数部分、またはその両方があります。署名されている場合があります。例: 1
、 .2
、 3.4
、 -5
、 -6.78
、 +9.10
。
近似値の数値リテラルは、仮数と指数を使用した科学表記法 (10 のべき乗) で表されます。どちらかまたは両方の部分に署名できます。例: 1.2E3
、 1.2E-3
、 -1.2E3
、 -1.2E-3
。
似ているように見える 2 つの数値が異なるように扱われる場合があります。たとえば、 2.34
は正確な値 (固定小数点) の数値ですが、 2.34E0
は近似値 (浮動小数点) の数値です。
DECIMAL データ型は固定小数点型であり、計算は正確です。 FLOAT および DOUBLE データ型は浮動小数点型であり、計算は近似値です。
DECIMAL データ型の特性
このセクションでは、DECIMAL データ型 (およびその同義語) の特性に関する次のトピックについて説明します。
- 最大桁数
- 保存形式
- ストレージ要件
DECIMAL 列の宣言構文はDECIMAL(M,D)
です。引数の値の範囲は次のとおりです。
- M は最大桁数 (精度) です。 1<= M <= 65。
- D は、小数点の右側の桁数 (スケール) です。 1 <= D <= 30、D は M 以下でなければなりません。
M の最大値 65 は、DECIMAL 値の計算が 65 桁まで正確であることを意味します。この 65 桁の精度制限は、正確な値の数値リテラルにも適用されます。
DECIMAL 列の値は、10 進数 9 桁を 4 バイトにパックするバイナリ形式を使用して格納されます。各値の整数部と小数部のstorage要件は個別に決定されます。 9 桁の各倍数には 4 バイトが必要で、残りの桁には 4 バイトの小数部分が必要です。残りの桁に必要なstorageは、次の表に示されています。
残りの数字 | バイト数 |
---|---|
0 | 0 |
1-2 | 1 |
3~4 | 2 |
5~6 | 3 |
7–9 | 4 |
たとえば、 DECIMAL(18,9)
列には小数点の両側に 9 桁があるため、整数部分と小数部分にそれぞれ 4 バイトが必要です。 DECIMAL(20,6)
列には 14 桁の整数桁と 6 桁の小数桁があります。整数の数字には、9 桁に 4 バイト、残りの 5 桁に 3 バイトが必要です。小数点以下 6 桁には 3 バイトが必要です。
DECIMAL 列には、先頭の+
文字、 -
文字、または先頭の0
桁は格納されません。 DECIMAL(5,1)
列に+0003.1
挿入すると、 3.1
として格納されます。負の数の場合、リテラルの-
文字は保存されません。
DECIMAL 列では、列定義によって暗示される範囲を超える値は許可されません。たとえば、 DECIMAL(3,0)
列は-999
~ 999
の範囲をサポートします。 DECIMAL(M,D)
列では、小数点の左側に最大M - D
桁が許可されます。
DECIMAL 値の内部形式の詳細については、TiDB ソース コードのmydecimal.go
を参照してください。
式の処理
精度の計算を伴う式の場合、TiDB は可能な限り指定された正確な値の数値を使用します。たとえば、比較における数値は、値を変更せずに指定されたとおりに使用されます。厳密な SQL モードでは、正確なデータ型を列に追加すると、列の範囲内にある数値がその正確な値とともに挿入されます。取得された場合、値は挿入された値と同じになります。厳密な SQL モードが有効になっていない場合、TiDB では INSERT の切り捨てが許可されます。
数値式の処理方法は、式の値によって異なります。
- 式に近似値が含まれている場合、結果は近似値になります。 TiDB は、浮動小数点演算を使用して式を評価します。
- 式に近似値が含まれていない場合、つまり正確な値のみが含まれており、正確な値に小数部分が含まれている場合、式は DECIMAL の正確な算術を使用して評価され、精度は 65 桁になります。
- それ以外の場合、式には整数値のみが含まれます。表現が的確ですね。 TiDB は整数演算を使用して式を評価し、精度は BIGINT (64 ビット) と同じになります。
数値式に文字列が含まれている場合、文字列は倍精度浮動小数点値に変換され、式の結果は近似値になります。
数値列への挿入は SQL モードの影響を受けます。以下の説明では、厳密モードとERROR_FOR_DIVISION_BY_ZERO
について説明します。すべての制限をオンにするには、厳密モード値とERROR_FOR_DIVISION_BY_ZERO
両方を含むTRADITIONAL
モードを使用するだけです。
SET sql_mode = 'TRADITIONAL`;
数値が正確な型の列 (DECIMAL または整数) に挿入される場合、その数値が列の範囲内にある場合は、その正確な値が挿入されます。この番号の場合:
- 値の小数部の桁数が多すぎる場合、四捨五入が発生し、警告が生成されます。
- 値の整数部分の桁数が多すぎる場合は、大きすぎるため、次のように処理されます。
- 厳密モードが有効になっていない場合、値は最も近い正当な値に切り捨てられ、警告が生成されます。
- 厳密モードが有効な場合、オーバーフロー エラーが発生します。
文字列を数値列に挿入するために、文字列に数値以外の内容が含まれている場合、TiDB は文字列から数値への変換を次のように処理します。
- strict モードでは、数字で始まらない文字列 (空の文字列を含む) を数字として使用できません。エラーまたは警告が発生します。
- 数字で始まる文字列は変換できますが、末尾の数字以外の部分は切り捨てられます。 strict モードでは、切り捨てられた部分にスペース以外のものが含まれている場合、エラーまたは警告が発生します。
デフォルトでは、0 による除算の結果は NULL になり、警告は表示されません。 SQLモードを適切に設定することで、0による除算を制限することができます。 ERROR_FOR_DIVISION_BY_ZERO
SQL モードを有効にすると、TiDB は 0 による除算を別の方法で処理します。
- strict モードでは、挿入と更新が禁止され、エラーが発生します。
- 厳密モードでない場合は、警告が表示されます。
次の SQL ステートメントでは次のようになります。
INSERT INTO t SET i = 1/0;
さまざまな SQL モードで次の結果が返されます。
sql_mode 値 | 結果 |
---|---|
」 | 警告もエラーもありません。 i は NULL に設定されます。 |
厳しい | 警告もエラーもありません。 i は NULL に設定されます。 |
ERROR_FOR_DIVISION_BY_ZERO | 警告、エラーはありません。 i は NULL に設定されます。 |
厳密、 ERROR_FOR_DIVISION_BY_ZERO | エラー;行は挿入されません。 |
丸め動作
ROUND()
関数の結果は、その引数が正確であるか近似であるかによって異なります。
正確な値の数値の場合、
ROUND()
関数は「四捨五入」ルールを使用します。近似値の数値については、TiDB の結果は MySQL の結果とは異なります。
TiDB > SELECT ROUND(2.5), ROUND(25E-1); +------------+--------------+ | ROUND(2.5) | ROUND(25E-1) | +------------+--------------+ | 3 | 3 | +------------+--------------+ 1 row in set (0.00 sec)
DECIMAL または整数列への挿入の場合、丸めには半分をゼロから四捨五入するが使用されます。
TiDB > CREATE TABLE t (d DECIMAL(10,0));
Query OK, 0 rows affected (0.01 sec)
TiDB > INSERT INTO t VALUES(2.5),(2.5E0);
Query OK, 2 rows affected, 2 warnings (0.00 sec)
TiDB > SELECT d FROM t;
+------+
| d |
+------+
| 3 |
| 3 |
+------+
2 rows in set (0.00 sec)