Какая разница, когда я использую типы данных float и decimal в MySQL?.
Когда мне следует использовать какой?
Какая разница, когда я использую типы данных float и decimal в MySQL?.
Когда мне следует использовать какой?
Это, что я нашел, когда у меня возникло это сомнение.
mysql> create table numbers (a decimal(10,2), b float);
mysql> insert into numbers values (100, 100);
mysql> select @a := (a/3), @b := (b/3), @a * 3, @b * 3 from numbers \G
*************************** 1. row ***************************
@a := (a/3): 33.333333333
@b := (b/3): 33.333333333333
@a + @a + @a: 99.999999999000000000000000000000
@b + @b + @b: 100
Десятичная величина сделала именно то, что должно было делать в этих случаях, это усекали остальных, тем самым теряя 1/3 часть.
Итак, для сумм десятичная величина лучше, но для делений float лучше, до некоторого момента, конечно. Я имею в виду, что использование DECIMAL не даст вы "непреодолимая арифметика" любым способом.
Надеюсь, это поможет.
"Поплавок" в большинстве сред - это двоичный тип с плавающей запятой. Он может точно хранить значения base-2 (до определенной точки), но не может точно хранить многие значения base-10 (десятичные). Поплавки наиболее подходят для научных расчетов. Они не подходят для большинства бизнес-ориентированных математики, и неправильное использование поплавков вас укусит. Многие десятичные значения не могут быть точно представлены в базе-2. 0.1
не может, например, и поэтому вы видите странные результаты, такие как 1.0 - 0.1 = 0.8999999
.
Десятичные числа хранят номера базы-10. Десятичное значение является хорошим типом для большинства бизнес-математик (но любой встроенный тип "деньги" более подходит для финансовых расчетов), где диапазон значений превышает тот, который предоставляется целыми типами, и необходимы дробные значения. Десятичные числа, как следует из названия, предназначены для чисел base-10 - они могут точно хранить десятичные значения (опять же, до определенной точки).
Недавно MySQL изменил их способ хранения DECIMAL type. В прошлом они сохраняли символы (или nybbles) для каждой цифры, содержащие ASCII (или nybble) представление числа - vs - целое двухкомпонентное число или его производное.
Текущий формат хранения для DECIMAL представляет собой последовательность из 1,2,3 или 4-байтовых целых чисел, чьи биты объединяются для создания двухдополнительных чисел с подразумеваемой десятичной точкой, определенных вами и сохраненных в схеме DB когда вы объявляете столбец и указываете его размер DECIMAL и положение десятичной точки.
В качестве примера, если вы берете 32-битный int, вы можете сохранить любое число от 0 до 4 294 967 295. Это будет надежно покрывать только 999,999,999, поэтому, если вы выбросили 2 бита и использовали (1 < 30 -1), вы ничего не отказались бы. Покрытие всех 9-значных чисел только с 4 байтами более эффективно, чем покрытие 4-х цифр в 32 битах с использованием 4 символов ASCII или 8 цифр. (nybble - 4-бит, позволяя значения 0-15, больше, чем необходимо для 0-9, но вы не можете устранить этот отход, перейдя на 3 бита, потому что это только покрывает значения 0-7)
В примере, используемом в онлайн-документах MySQL, используется DECIMAL (18,9). Это 9 цифр впереди и 9 цифр за подразумеваемой десятичной точкой, что, как объяснено выше, требует следующего хранилища.
Как 18 8-битных символов: 144 бит
Как 18 4-битных nybbles: 72 бит
Как 2 32-битных целых числа: 64 бит
В настоящее время DECIMAL поддерживает максимум 65 цифр, так как DECIMAL (M, D), где наибольшее значение для M разрешено - 65, а наибольшее значение D разрешено 30.
Чтобы не требовать кусков по 9 цифр за раз, целые числа меньше 32 бит используются для добавления цифр с использованием 1,2 и 3 байтовых целых чисел. По какой-то причине, которая игнорирует логику, подписали вместо вместо unsigned ints, и при этом 1 бит выкидывается, что приводит к следующим возможностям хранения. Для 1,2 и 4 байтов ints потерянный бит не имеет значения, но для 3-байтового int это катастрофа, потому что целая цифра теряется из-за потери этого единственного бита.
С 7-битным int: 0 - 99
С 15-битным int: 0 - 9,999
С 23-битным int: 0 - 999 999 (0 - 9999999 с 24-битным int)
1,2,3 и 4-байтовые целые числа объединяются вместе, чтобы сформировать "бит-пул", используемый DECIMAL для представления числа точно как целое целое число. Десятичная точка НЕ хранится, это подразумевается.
Это означает, что не требуется преобразование ASCII в int для механизма БД, чтобы преобразовать "число" во что-то, что ЦП распознает как число. Без округления, без ошибок преобразования, это реальный номер, который может манипулировать ЦП.
Вычисления по этому произвольно большому целому числу должны выполняться в программном обеспечении, так как нет аппаратной поддержки для такого рода номеров, но эти библиотеки очень старые и сильно оптимизированы, написано 50 лет назад для поддержки произвольной точности IBM 370 Fortran данные с плавающей запятой. Они все еще намного медленнее, чем целая алгебра фиксированного размера, выполненная с использованием целочисленного аппаратного обеспечения ЦП или вычисления с плавающей запятой, выполненные на FPU.
С точки зрения эффективности хранения, поскольку показатель числа float привязан к каждому поплату, неявно определяя, где находится десятичная точка, он является массово избыточным и, следовательно, неэффективным для работы с БД. В БД вы уже знаете, где десятичная точка должна идти вверх, и каждая строка в таблице, которая имеет значение для столбца DECIMAL, должна смотреть только на 1 и только спецификацию того, где должна быть размещена эта десятичная точка, сохранена в схеме как аргументы DECIMAL (M, D) как импликация значений M и D.
Много замечаний, которые можно найти здесь, о том, какой формат будет использоваться для различных приложений, верны, поэтому я не буду расстраивать этот вопрос. Я потратил время, чтобы написать это здесь, потому что тот, кто поддерживает связанную онлайн-документацию MySQL, не понимает ни одного из вышеперечисленных и после раундов все более разочаровывающих попыток объяснить это им, я сдался. Хорошим показателем того, насколько плохо они понимали, что они пишут, является очень запутанное и почти неразборчивое изложение предмета.
В качестве последней мысли, если вам нужно высокоточное вычисление с плавающей запятой, за последние 20 лет произошли огромные успехи в области с плавающей запятой, а аппаратная поддержка для 96-битных и Quadruple Precision floatнаходятся за углом, но там есть хорошие библиотеки точности точности, если важна манипуляция хранимым значением.
Не только для MySQL, разница между типами float и decimal - это то, как они представляют дробные значения. Типы с плавающей точкой представляют дробные части в двоичном формате, которые могут представлять только значения как {m*2^n | m, n Integers}
. значения, такие как 1/5, не могут быть точно представлены (без ошибки округления). Десятичные числа аналогично ограничены, но представляют числа, такие как {m*10^n | m, n Integers}
. Десятичные числа по-прежнему не могут представлять числа, такие как 1/3, но часто во многих распространенных областях, таких как финансы, ожидают, что определенные десятичные дроби всегда могут быть выражены без потери верности. Поскольку десятичное число может представлять значение, подобное $0.20
(одна пятая от доллара), это предпочтительнее в таких ситуациях.
decimal для фиксированных величин, таких как деньги, где вы хотите указать определенное количество знаков после запятой. Поплавки предназначены для хранения... чисел точности с плавающей запятой.
mysql> CREATE TABLE num(id int ,fl float,dc dec(5,2));
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO num VALUES(1,13.75,13.75);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO num VALUES(2,13.15,13.15);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM num WHERE fl = 13.15;
Empty set (0.00 sec)
mysql> SELECT * FROM num WHERE dc = 13.15;
+------+-------+-------+
| id | fl | dc |
+------+-------+-------+
| 2 | 13.15 | 13.15 |
+------+-------+-------+
1 row in set (0.00 sec)
mysql> SELECT SUM(fl) ,SUM(dc) FROM num;
+--------------------+---------+
| SUM(fl) | SUM(dc) |
+--------------------+---------+
| 26.899999618530273 | 26.90 |
+--------------------+---------+
1 row in set (0.00 sec)
mysql> SELECT * FROM num WHERE ABS(fl - 13.15)<0.01;
+------+-------+-------+
| id | fl | dc |
+------+-------+-------+
| 2 | 13.15 | 13.15 |
+------+-------+-------+
1 row in set (0.00 sec)
Float:
Небольшое (одноточечное) число с плавающей запятой. Допустимые значения: -3.402823466E + 38 до -1.175494351E-38,0 и 1,1775494351E-38 до 3,402823466E + 38. Эти теоретические пределы, основанные на стандарте IEEE. Фактический диапазон может быть немного меньше в зависимости от вашего оборудования или операционной системы.
DECIMAL:
Упакованное "точное" число с фиксированной запятой. M - общее количество цифр (точность), а D - количество цифр после десятичной точки (масштаб). Десятичная точка и (для отрицательных чисел) знак "-" не учитывается в М. Если D равно 0, значения не имеют десятичной или дробной части. Максимальное количество цифр (M) для DECIMAL равно 65. Максимальное количество поддерживаемых десятичных знаков (D) равно 30. Если D опущено, значение по умолчанию равно 0. Если M опущено, по умолчанию 10.
Я нашел это полезным:
Как правило, значения Float хороши для научных вычислений, но не должны использоваться для финансовых/валютных ценностей. Для бизнес-ориентированной математики всегда используйте Decimal.
Источник: http://code.rohitink.com/2013/06/12/mysql-integer-float-decimal-data-types-differences/
Если вы после производительности, а не точности, вы должны заметить, что вычисления с поплавками намного быстрее, чем десятичные знаки
Типы с плавающей точкой (приблизительное значение) - FLOAT, DOUBLE
Типы FLOAT и DOUBLE представляют значения приблизительные числовые данные. MySQL использует четыре байта для значений с одной точностью и восемь байтов для значений двойной точности.
Для FLOAT стандарт SQL допускает необязательную спецификацию точности (но не диапазон показателя) в битах, следующих за ключевым словом FLOAT в круглых скобках. MySQL также поддерживает эту необязательную спецификацию точности, но значение точности используется только для определения размера хранилища. Точность от 0 до 23 приводит к 4-байтовой колонке FLOAT с одной точностью. Точность от 24 до 53 приводит к 8-байтовой колонке с двойной точностью DOUBLE.
MySQL допускает нестандартный синтаксис: FLOAT (M, D) или REAL (M, D) или DOUBLE PRECISION (M, D). Здесь "(M, D)" означает, что значения могут быть сохранены с суммой до M цифр, из которых D цифр могут быть после десятичной точки. Например, столбец, определенный как FLOAT (7,4), будет отображаться как -999.9999 при отображении. MySQL выполняет округление при сохранении значений, поэтому, если вы вставляете 999.00009 в столбец FLOAT (7,4), приблизительный результат равен 999.0001.
Поскольку значения с плавающей запятой являются приблизительными и не сохраняются в виде точных значений, попытки рассматривать их как точные в сравнении могут привести к проблемам. Они также зависят от зависимостей платформы или реализации.
Для максимальной переносимости код, требующий хранения приблизительных значений числовых данных, должен использовать FLOAT или DOUBLE PRECISION без указания точности или количества цифр.
https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html
Проблемы с значениями с плавающей запятой
Числа с плавающей запятой иногда вызывают путаницу, потому что они являются приблизительными и не сохраняются как точные значения. Значение с плавающей запятой, как указано в инструкции SQL, может быть не таким, как значение, представленное внутри. Попытки рассматривать значения с плавающей запятой как точные в сравнении могут привести к проблемам. Они также зависят от зависимостей платформы или реализации. Эти типы вопросов относятся к типам данных FLOAT и DOUBLE. Для столбцов DECIMAL MySQL выполняет операции с точностью до девяти десятичных цифр, что должно решить наиболее распространенные проблемы неточности.
В следующем примере DOUBLE демонстрирует, как вычисления, выполняемые с использованием операций с плавающей запятой, подвержены ошибкам с плавающей запятой.
mysql> CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql> INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
-> (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
-> (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
-> (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
-> (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
-> (6, 0.00, 0.00), (6, -51.40, 0.00);
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b
-> FROM t1 GROUP BY i HAVING a <> b;
+------+-------+------+
| i | a | b |
+------+-------+------+
| 1 | 21.4 | 21.4 |
| 2 | 76.8 | 76.8 |
| 3 | 7.4 | 7.4 |
| 4 | 15.4 | 15.4 |
| 5 | 7.2 | 7.2 |
| 6 | -51.4 | 0 |
+------+-------+------+
Результат правильный. Хотя первые пять записей выглядят так, что они не должны удовлетворять сравнению (значения a и b не кажутся разными), они могут это сделать, потому что разница между числами отображается примерно в десятом десятичном значении или около того, в зависимости от факторов таких как компьютерная архитектура или версия компилятора или уровень оптимизации. Например, разные ЦП могут оценивать числа с плавающей запятой по-разному.
Если столбцы d1 и d2 были определены как DECIMAL, а не DOUBLE, результат запроса SELECT содержал бы только одну строку - последнюю показанную выше.
Правильный способ сравнения чисел с плавающей запятой состоит в том, чтобы сначала принять приемлемый допуск для различий между числами, а затем выполнить сравнение с допустимым значением. Например, если мы согласны с тем, что числа с плавающей запятой следует рассматривать одинаково, если они одинаковы в пределах одной десятитысячной (0,0001), сравнение должно быть записано, чтобы найти различия, превышающие значение допуска:
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
-> GROUP BY i HAVING ABS(a - b) > 0.0001;
+------+-------+------+
| i | a | b |
+------+-------+------+
| 6 | -51.4 | 0 |
+------+-------+------+
1 row in set (0.00 sec)
И наоборот, чтобы получить строки, где числа совпадают, тест должен найти различия в пределах допустимого значения:
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
-> GROUP BY i HAVING ABS(a - b) <= 0.0001;
+------+------+------+
| i | a | b |
+------+------+------+
| 1 | 21.4 | 21.4 |
| 2 | 76.8 | 76.8 |
| 3 | 7.4 | 7.4 |
| 4 | 15.4 | 15.4 |
| 5 | 7.2 | 7.2 |
+------+------+------+
5 rows in set (0.03 sec)
Значения с плавающей запятой зависят от зависимостей платформы или реализации. Предположим, что вы выполняете следующие инструкции:
CREATE TABLE t1(c1 FLOAT(53,0), c2 FLOAT(53,0));
INSERT INTO t1 VALUES('1e+52','-1e+52');
SELECT * FROM t1;
На некоторых платформах оператор SELECT возвращает inf и -inf. На других он возвращает 0 и -0.
Примером предшествующих проблем является то, что если вы попытаетесь создать ведомое устройство репликации, сбросив содержимое таблицы с помощью mysqldump на главном сервере и перезагрузив файл дампа в подчиненный, таблицы, содержащие столбцы с плавающей запятой, могут отличаться между двумя хостами.
https://dev.mysql.com/doc/refman/5.5/en/problems-with-float.html
Жесткое и быстрое правило
Если вам нужно всего лишь добавить, вычесть или умножить числа, которые вы храните, лучше всего использовать DECIMAL.
Если вам нужно разделить или сделать любую другую арифметику или алгебру на данных, вы почти наверняка будете счастливы с float. Библиотеки с плавающей запятой, а также процессоры Intel, процессор с плавающей запятой, имеют TON операций для исправления, исправления, обнаружения и обработки метели исключений, возникающих при выполнении типичных математических функций - особенно трансцендентных функций.
Что касается точности, я как-то написал бюджетную систему, которая рассчитала% вклада каждой из 3 000 + учетных записей на 3600 единиц бюджета по месяцам на эту консолидацию единиц node, а затем на основе этой матрицы процентов (3000 + x 12 x 3,600). Я умножил суммы, предусмотренные бюджетом на наивысшие организационные узлы, до следующих 3 уровней организационных узлов, а затем вычислил все (3000 + 12) значений для всех 3200 единиц детали из этого. Миллионы и миллионы и миллионы вычислений с плавающей запятой с двойной точностью, любой из которых отбросил бы свертывание всех этих прогнозов в консолидированной консолидации до самого высокого уровня в организации.
Общая ошибка с плавающей запятой после всех этих вычислений была ZERO. Это было в 1986 году, и сегодня библиотеки с плавающей запятой намного лучше, чем они были тогда. Intel делает все это промежуточные вычисления удвоений в 80-битной точности, что почти исключает ошибку округления. Когда кто-то говорит вам "это ошибка с плавающей запятой", это почти наверняка НЕ истинно.
float
(и double
) представляет двоичные дроби
decimal
представляет десятичные дроби
declare @float as float(10)
declare @Decimal as decimal(10)
declare @Inetger as int
set @float =10.7
set @Decimal =10.7
set @[email protected]
print @Inetger
в float, когда заданное значение для целочисленной печати 10 но в десятичном значении 11