重要
このページは英語版のページを機械翻訳しています。原文はこちらからご覧ください。

精密計算

TiDBでの高精度の数学サポートは、MySQLと一貫性があります。詳細については、 MySQLの精密計算を参照してください。

数値タイプ

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

正確な値の数値リテラルには、整数部分または小数部分、あるいはその両方があります。それらは署名されるかもしれません。 -5 -6.78 1 +9.10 .2 3.4

近似値の数値リテラルは、仮数と指数を使用した科学的記数法(10の累乗)で表されます。いずれかまたは両方の部分に署名することができます。 1.2E-3 -1.2E3 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バイトにパックするバイナリ形式を使用して格納されます。各値の整数部分と小数部分のストレージ要件は、個別に決定されます。 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の範囲をサポートし999DECIMAL(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または整数)に挿入される場合、その列の範囲内であれば、その正確な値とともに挿入されます。この番号の場合:

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

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

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

デフォルトでは、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)