Почему MySQL Round плавает намного больше, чем ожидалось?

UPDATE some_table SET some_float_field=1919.987 WHERE id=123

SELECT * FROM some_table WHERE id=123

где some_float_field - это поле, определенное как "float" (без каких-либо конкретных значений размера).

Ожидаемое итоговое значение будет 1919,987; вместо этого он округляется до 1919,99

Зачем? 32-битное (одинарная точность) число с плавающей точкой имеет достаточную точность для правильного хранения!

2 ответа

Решение

Когда вы запускаете запрос:

SELECT * FROM some_table WHERE id = 123

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

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

select format(some_float_field, 3)

преобразует это в строку с тремя десятичными разрядами. Одно предостережение: он также добавит запятые, которые вы можете не захотеть. Это также должно работать:

select cast(some_float_field as decimal(8, 3))

также должен сделать свое дело.

Обратите внимание, что вы можете легко проверить правильность данных, выполнив что-то вроде:

select *
from some_table
where some_float_field between 1919.987 - 0.0001 and 1919.987 + 0.0001;

Обратите внимание, что вы не хотите использовать = на значениях с плавающей запятой, но вы уже это понимаете.

Из руководства FLOAT:

FLOAT а также DOUBLE типы представляют приблизительные числовые значения данных. MySQL использует четыре байта для значений одинарной точности.

Упор здесь лежит на приблизительный. Если вам нужно хранить точные значения, вы должны использовать DECIMAL тип данных.

За FLOAT MySQL использует стандарт IEEE 754 для двоичной арифметики с плавающей запятой, чтобы "сжать" любую дробь числа в 4 байта (или 8, для DOUBLE).

Обратите внимание, что это применяется к любому значению, независимо от того, может ли значение (десятичная часть и дробь) быть точно представлено в 4 байтах! Например, представление 0,01 в плавающей запятой в точности равно 0,009999999776482582092285156250 - даже если 0,01 идеально поместится в 32-разрядной памяти, используя другой формат хранения.

Википедия довольно хорошо объясняет концепцию с плавающей точкой.

Обратите внимание, что на алгоритм влияет точность, указанная в определении столбца.
Посмотрите этот пример SQL-скрипки.

Другие вопросы по тегам