このセクションでは、MySQL 5.1 における精密計算に対するクエリ結果を示す例を紹介します。
例1。数には、出来るだけ、与えられた通りの正確な価が使われている:
mysql> SELECT .1 + .2 = .3;
+--------------+
| .1 + .2 = .3 |
+--------------+
| 1 |
+--------------+
浮動点値に対する結果は不正確です。
mysql> SELECT .1E0 + .2E0 = .3E0;
+--------------------+
| .1E0 + .2E0 = .3E0 |
+--------------------+
| 0 |
+--------------------+
正確値の扱いと近似値の扱いの違いを調べる別の方法は、合計に何回も小さい数字を加える事です。変数に
.0001
を1,000回加える、以下のストアド
プロシージャを考慮してみてください。
CREATE PROCEDURE p () BEGIN DECLARE i INT DEFAULT 0; DECLARE d DECIMAL(10,4) DEFAULT 0; DECLARE f FLOAT DEFAULT 0; WHILE i < 10000 DO SET d = d + .0001; SET f = f + .0001E0; SET i = i + 1; END WHILE; SELECT d, f; END;
d
と f
両方に対する合計は論理的には1であるべきですが、それは小数計算についてだけ言える事です。浮動点計算は小さなエラーを引き起こします:
+--------+------------------+ | d | f | +--------+------------------+ | 1.0000 | 0.99999999999991 | +--------+------------------+
例2。乗算はスタンダード
SQL
によって要求されたスケールで実施されます。すなわち、スケール
S1
と S2
を持つ2つの数、X1
と
X2
に対して、結果のスケールは
です。
S1
+
S2
mysql> SELECT .01 * .01;
+-----------+
| .01 * .01 |
+-----------+
| 0.0001 |
+-----------+
例3。丸め挙動はよく定義されています。
丸め挙動 (例えば、ROUND()
関数を使用)は基礎をなしている C
ライブラリのインプリメンテーションから独立していて、それは、結果はプラットホームが変わっても一貫している事を意味します。
正確な値のカラム(DECIMAL
と整数)と正確な値の数に対する丸めには、「round
half up」 規則が使われます。.5
以上の端数を持つ値は、ここに示すように、ゼロから最も近い整数に丸められます。
mysql> SELECT ROUND(2.5), ROUND(-2.5);
+------------+-------------+
| ROUND(2.5) | ROUND(-2.5) |
+------------+-------------+
| 3 | -3 |
+------------+-------------+
しかしながら、浮動小数点値の丸めには、多くのシステム上で 「round to nearest even」 規則を使用している C ライブラリが使用されます。このようなシステム上の端数付きの値は最も近い偶整数に丸められます。
mysql> SELECT ROUND(2.5E0), ROUND(-2.5E0);
+--------------+---------------+
| ROUND(2.5E0) | ROUND(-2.5E0) |
+--------------+---------------+
| 2 | -2 |
+--------------+---------------+
例4。ストリクト モードでは、大き過ぎる値を挿入すると、結果はオーバーフローとなり、法的な値に切り下げる事なく、エラーを引き起こします。
MySQL がストリクト モードで運転されていない時には、法的な値への切り捨てが起こります:
mysql>SET sql_mode='';
Query OK, 0 rows affected (0.00 sec) mysql>CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.01 sec) mysql>INSERT INTO t SET i = 128;
Query OK, 1 row affected, 1 warning (0.00 sec) mysql>SELECT i FROM t;
+------+ | i | +------+ | 127 | +------+ 1 row in set (0.00 sec)
しかし、ストリクト モードが有効であると、オーバーフロー条件が発生します。
mysql>SET sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected (0.00 sec) mysql>CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.00 sec) mysql>INSERT INTO t SET i = 128;
ERROR 1264 (22003): Out of range value adjusted for column 'i' at row 1 mysql>SELECT i FROM t;
Empty set (0.00 sec)
例 5。ストリクト
モードにして ERROR_FOR_DIVISION_BY_ZERO
をセットすると、ゼロによる除算がエラーを引き起こし、NULL
の結果は得られません。
非ストリクト
モードにすると、ゼロによる除算が
NULL
の結果をもたらします:
mysql>SET sql_mode='';
Query OK, 0 rows affected (0.01 sec) mysql>CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.00 sec) mysql>INSERT INTO t SET i = 1 / 0;
Query OK, 1 row affected (0.00 sec) mysql>SELECT i FROM t;
+------+ | i | +------+ | NULL | +------+ 1 row in set (0.03 sec)
しかし、適当な SQL モードを有効にすると、ゼロによる除算はエラーとなります。
mysql>SET sql_mode='STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO';
Query OK, 0 rows affected (0.00 sec) mysql>CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.00 sec) mysql>INSERT INTO t SET i = 1 / 0;
ERROR 1365 (22012): Division by 0 mysql>SELECT i FROM t;
Empty set (0.01 sec)
例6。MySQL 5.0.3より前のバージョン(精密計算が導入る前)では、正確値リテラルと近似値リテラルは両方共、ダブル精密浮動点値に変換されます。
mysql>SELECT VERSION();
+------------+ | VERSION() | +------------+ | 4.1.18-log | +------------+ 1 row in set (0.01 sec) mysql>CREATE TABLE t SELECT 2.5 AS a, 25E-1 AS b;
Query OK, 1 row affected (0.07 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql>DESCRIBE t;
+-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | a | double(3,1) | | | 0.0 | | | b | double | | | 0 | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.04 sec)
MySQL
5.0.3以降のバージョンでは、近似値リテラルは浮動点に変換されますが、正確値リテラルは
DECIMAL
として処理されます。
mysql>SELECT VERSION();
+-----------------+ | VERSION() | +-----------------+ | 5.1.6-alpha-log | +-----------------+ 1 row in set (0.11 sec) mysql>CREATE TABLE t SELECT 2.5 AS a, 25E-1 AS b;
Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql>DESCRIBE t;
+-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | a | decimal(2,1) unsigned | NO | | 0.0 | | | b | double | NO | | 0 | | +-------+-----------------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
例7。総計関数に対する引数が正確な数値タイプの物である場合、その結果も、少なくとも引数に等しいスケールの正確な数値タイプの物となります。
これらのステートメントを考慮してみてください:
mysql>CREATE TABLE t (i INT, d DECIMAL, f FLOAT);
mysql>INSERT INTO t VALUES(1,1,1);
mysql>CREATE TABLE y SELECT AVG(i), AVG(d), AVG(f) FROM t;
MySQL 5.0.3 (精密計算が MySQL の中に導入される以前の)での結果:
mysql> DESCRIBE y;
+--------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| AVG(i) | double(17,4) | YES | | NULL | |
| AVG(d) | double(17,4) | YES | | NULL | |
| AVG(f) | double | YES | | NULL | |
+--------+--------------+------+-----+---------+-------+
引数のタイプに関係なく、結果はダブルとなります。
MySQL 5.0.3による結果:
mysql> DESCRIBE y;
+--------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| AVG(i) | decimal(14,4) | YES | | NULL | |
| AVG(d) | decimal(14,4) | YES | | NULL | |
| AVG(f) | double | YES | | NULL | |
+--------+---------------+------+-----+---------+-------+
結果は、浮動点引数に対してだけダブルとなります。正確なタイプの引数の場合、結果も正確なタイプの物となります。