Spec-Zone .ru
спецификации, руководства, описания, API

12.19.5. Математические Примеры точности

Этот раздел обеспечивает некоторые примеры, которые показывают математические результаты запроса точности в MySQL 5.7. Эти примеры демонстрируют принципы, описанные в Разделе 12.19.3, "Обработка Выражения", и Раздел 12.19.4, "Округление Поведения".

Пример 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. Таким образом, для двух чисел X1 и X2 у этого есть масштаб S1 и S2, масштаб результата S1 + S2:

mysql> SELECT .01 * .01;+-----------+| .01 * .01 |+-----------+| 0.0001    |+-----------+

Пример 3. Округление поведения для чисел точного значения четко определено:

Округление поведения (например, с ROUND() функция), независимо от реализации базовой библиотеки C, что означает, что результаты являются непротиворечивыми от платформы до платформы.

Пример 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 1mysql> 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 0mysql> 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: 0mysql> 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: 0mysql> 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> 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    |       |+--------+---------------+------+-----+---------+-------+

Результатом является двойное только для параметра с плавающей точкой. Для точных параметров типа результатом является также точный тип.