精密計算

TiDB での精度計算のサポートは、MySQL と一致しています。詳細については、 MySQL の精密計算を参照してください。

数値型

正確な値の演算の精度計算の範囲には、正確な値のデータ型 (整数および DECIMAL 型) と正確な値の数値リテラルが含まれます。近似値データ型および数値リテラルは、浮動小数点数として扱われます。

正確な値の数値リテラルには、整数部分または小数部分、あるいはその両方があります。署名されている場合があります。例: 1.23.4-5-6.78+9.10

近似値の数値リテラルは、仮数と指数を使用して指数表記 (10 の累乗) で表されます。いずれかまたは両方の部分に署名することができます。例: 1.2E31.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 列の値は、9 桁の 10 進数を 4 バイトにパックするバイナリ形式を使用して格納されます。各値の整数部分と小数部分のストレージ要件は、個別に決定されます。 9 桁の倍数ごとに 4 バイトが必要で、残りの桁には 4 バイトの端数が必要です。残りの桁に必要なストレージを次の表に示します。

残りの数字バイト数
00
1–21
3–42
5–63
7–94

たとえば、 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 モードの影響を受けます。以下の説明では、strict モードとERROR_FOR_DIVISION_BY_ZEROについて言及しています。すべての制限をオンにするには、strict モード値とERROR_FOR_DIVISION_BY_ZEROの両方を含むTRADITIONALモードを使用するだけです。

SET sql_mode = 'TRADITIONAL`;

数値が正確なタイプの列 (DECIMAL または整数) に挿入される場合、列の範囲内にある場合は正確な値と共に挿入されます。この番号の場合:

  • 値の小数部分の桁数が多すぎる場合、丸めが行われ、警告が生成されます。
  • 値の整数部分の桁数が多すぎる場合は、大きすぎるため、次のように処理されます。
    • 厳密モードが有効になっていない場合、値は最も近い正当な値に切り捨てられ、警告が生成されます。
    • 厳密モードが有効になっている場合、オーバーフロー エラーが発生します。

文字列を数値列に挿入するために、文字列に数値以外の内容が含まれている場合、TiDB は次のように文字列から数値への変換を処理します。

  • 厳密モードでは、数値で始まらない文字列 (空文字列を含む) は数値として使用できません。エラーまたは警告が発生します。
  • 数字で始まる文字列は変換できますが、末尾の数字以外の部分は切り捨てられます。厳密モードでは、切り捨てられた部分にスペース以外が含まれていると、エラーまたは警告が発生します。

デフォルトでは、0 による除算の結果は NULL であり、警告はありません。 SQL モードを適切に設定することで、0 による除算を制限できます。 ERROR_FOR_DIVISION_BY_ZERO SQL モードを有効にすると、TiDB は 0 による除算を別の方法で処理します。

  • 厳密モードでは、挿入と更新が禁止され、エラーが発生します。
  • 厳密モードでない場合は、警告が発生します。

次の 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)