SQLinfo.ru - Все о MySQL Webew.ru: теория и практика веб-технологий

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 16.11.2021 23:55:01

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 839

Небольшая история о преобразовании числовых строк в числа

Всегда знал, что 'число' и число - разные вещи, но за всё время своей работы с MySQL ни разу не бывал в ситуации, когда эта разница играет роль. И вот недавно такое случилось, о чем хочу рассказать.

Если вкратце: разница может сыграть роль, когда такие величины участвуют в арифметических операциях умножения или деления.

В моём случае нужно было рассчитать цену на товар со скидкой 55%. Что, как известно, делается по простой формуле:

Код:

цена со скидкой = ROUND( цена без скидки * (1 - скидка/100) )

Случайная проверка выявила расхождение цены из базы данных и цены, посчитанной вручную на калькуляторе. При разборе формулы на части выяснилась неожиданная вещь:

Код:

mysql> SELECT 55/100, 1 - 55/100, '55'/100, 1 - '55'/100;
+--------+------------+----------+---------------------+
| 55/100 | 1 - 55/100 | '55'/100 | 1 - '55'/100        |
+--------+------------+----------+---------------------+
| 0.5500 |     0.4500 |     0.55 | 0.44999999999999996 |
+--------+------------+----------+---------------------+

Как я понял, операция с числами дала результат типа DECIMAL - точное число, а операция с числами и строкой - FLOAT, число с плавающей точкой. Из-за различий в механизме их хранения возникло расхождение фактических величин.

На практике это привело к двум разным ценам:

Код:

29990 * 0.4500 = 13495.5000; после округления - 13496
29990 * 0.44999999999999996 = 13495.499999999998; после округления - 13495

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

Если подобная величина отправляется в делитель, то и здесь возникают различия:

Код:

mysql> SELECT 1/55, 1/'55';
+--------+---------------------+
| 1/55   | 1/'55'              |
+--------+---------------------+
| 0.0182 | 0.01818181818181818 |
+--------+---------------------+

Вот такая история.

Неактивен

 

#2 30.11.2021 18:48:08

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3861

Re: Небольшая история о преобразовании числовых строк в числа

Спасибо! Интересный эффект. Действительно, явное преобразование во FLOAT дает такой же результат.

Код:

mysql> select 1-CAST(55 AS FLOAT)/100.;
+--------------------------+
| 1-CAST(55 AS FLOAT)/100. |
+--------------------------+
|      0.44999999999999996 |
+--------------------------+

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson