![]() |
Задавайте вопросы, мы ответим
Вы не зашли.
Страниц: 1
Всегда знал, что 'число' и число - разные вещи, но за всё время своей работы с 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 | +--------+---------------------+
Вот такая история.
Неактивен
Спасибо! Интересный эффект. Действительно, явное преобразование во FLOAT дает такой же результат.
mysql> select 1-CAST(55 AS FLOAT)/100.; +--------------------------+ | 1-CAST(55 AS FLOAT)/100. | +--------------------------+ | 0.44999999999999996 | +--------------------------+
Неактивен
Страниц: 1