Выполняю запрос к БД MySQL, чтобы получить проценты за платеж:
select cp.id,
cp.percent,
round(cp.percent, 2)
from payment cp
where cp.id = 4118098
and month(cp.payment_date) = 9
Выдаёт:
Вопрос: почему округление до сотых округляет вниз, хотя на конце цифра 5?
При этом запрос select round(75.725, 2)
округляет всё корректно - до 75.73.
Тип столбца percent
в таблице как double
.
почему округление до сотых округляет вниз, хотя на конце цифра 5?
Тип столбца percent в таблице как double.
Тип DOUBLE относится к т.н. "неточным" типам данных - т.е. используемое для его хранения двоичное представление не в точности равно введённому, а лишь максимально близко к нему. Как итог - печально известные 0,1000000001 или 0,0999999999 вместо введённого изначально 0,1. И false при сравнении такого значения с непосредственно заданным в виде литерала значением 0,1.
В соответствии с документацией для таких типов данных
For approximate-value numbers, the result depends on the C library. On many systems, this means that ROUND() uses the “round to nearest even” rule: A value with a fractional part exactly halfway between two integers is rounded to the nearest even integer.
или, если по-русски, "результат округления зависит от используемой библиотеки функций, во многих случаях выполняется округление к ближайшему чётному" (т.н. "бухгалтерское" округление).
Для того, чтобы получить округление "половина - вверх", необходимо привести сначала имеющееся значение к "точному" числовому типу, т.е. желаемое округление можно было бы получить так:
SELECT ROUND(CAST(cp.percent AS DECIMAL(6,3)), 2)
Однако приведение типа само по себе требует округления (помним, что исходное значение-то у нас неточное!), а потому есть смысл сразу выполнять приведение к нужному конечному типу, т.е. с нужным количеством десятичных знаков. И окончательный вариант будет выглядеть как
SELECT CAST(cp.percent AS DECIMAL(5,2))
При этом запрос select round(75.725, 2) округляет всё корректно - до 75.73.
В данном случае константа-литерал сразу создаётся с типом DECIMAL. Потому и округление работает, как указано в той же документации:
For exact-value numbers, ROUND() uses the “round half away from zero” or “round toward nearest” rule: A value with a fractional part of .5 or greater is rounded up to the next integer if positive or down to the next integer if negative. (In other words, it is rounded away from zero.) A value with a fractional part less than .5 is rounded down to the next integer if positive or up to the next integer if negative.
или, если по-русски, "округление к ближайшему целому в направлении от нуля", т.е. положительные - вверх, а отрицательные - вниз.
PS. Обратите внимание - функции преобразования типа CAST() и CONVERT() вообще не предусматривают приведения числа к неточному числовому типу.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Только в хроме наблюдается проблема с отображением кнопки - полоски вертикальныеПомогите их убрать
Изображения одинакового размера, но не становятся в один ряд по горизонтали
Имеется условный флексовый div, в нём 4 элементаПри уменьшении разрешения экрана, соответственно и уменьшении div'а, необходимо что бы сдвигались...