В MySQL у меня есть следующая формула:

SELECT FLOOR(38774/184*126*23+0.5);

Который , к моему удивлению дает 610690 , даже если результат формулы внутри FLOOR является 610691 В Excel это работает просто отлично и дает мне желаемый результат, также в любом калькуляторе, который я использую на macOS или Windows.

Я что-то пропускаю здесь? Есть ли объяснение этому поведению и, что более важно, как я могу предотвратить это?

1 ответ1

0

Вычисления с плавающей запятой - довольно забавная вещь: попробуйте следующее:

SELECT FLOOR(38774/184*126*23+0.5);
SELECT FLOOR(38774*126*23/184+0.5);
SELECT FLOOR(ROUND(38774/184*126*23+0.5, 3));

Что тут происходит?

Самая важная часть состоит в том, что 38774/184 не имеет точного представления в виде числа с плавающей запятой - вы всегда и чуть-чуть меньше. С остальным расчетом добавления точно до 610691, вы в конечном итоге крошечные немного меньше 610691 в результате чего FLOOR 610690.

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

Третья строка использует ROUND чтобы обрезать очень маленькую разницу, таким образом, заставляя FLOOR работать как положено.

Практическое правило. Числа с плавающей точкой не дают точных результатов. Хотя они чаще всего являются "достаточно точными", существуют крайние случаи, когда это не так. Вы просто ударил одного, а вполне обычный один: Преобразование обратно в целое через FLOOR или CEIL

Теперь, чтобы ответить на ваш вопрос: исходя из опыта, я бы приказал вычислить так, как это делает 2-я строка - большие числа (в пределах диапазона INT32) с гораздо большей вероятностью приведут к правильному FLOOR . Если вычислительная стоимость приемлема для вас, я бы пошел на

SELECT FLOOR(ROUND(38774*126*23/184+0.5, 3));

и будьте вполне уверены, что все крайние случаи покрыты.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .