Різниця між плаваючим і десятковим типом даних


175

Яка різниця, коли я використовую float і decimal типи даних у MySQL ?.

Коли я повинен використовувати який?


Не використовуйте FLOAT(m,n), це призводить до двох округлення; тим часом він не дає нічого корисного.
Рік Джеймс

Відповіді:


185

Це те, що я виявив, коли у мене виникли ці сумніви.

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 частини.

Так що для сум десяткова краща, але для поділів поплавок краще, звичайно, до певного моменту. Я маю на увазі, використання DECIMAL не дасть вам арифметики "не довести до ладу" жодними засобами.

Сподіваюся, це допомагає.


4
Прекрасне випробування. Роки тому функції перетворення даних C lib часто створювали б тонну хвилинну різницю значень, перетворених з ASCII в плавні, порівняно із значеннями, скажімо, у SQLServer. Це рідко вже так. Тестування - найкраща політика, оскільки найкраще точно знати, що таке компроміси.

15
Насправді додаток DECIMAL є помилковим. Якщо додати 33,333333333 тричі, ви не отримаєте 100. Якщо ділити 100 на 3, ви не отримаєте раціональне число без повторюваного набору проміжних цифр, тому ви не зможете помножити його на 3 і отримати 100. Вийдіть калькулятор і спробуйте. За логікою ми знаємо, що 1/3 + 1/3 + 1/3 повинна дорівнювати 3 / 3r IE: 1, але цей клас раціональних чисел не дозволяє нам це робити. Плаваюча відповідь правильна, але ваш бухгалтер ненавидить її !
користувач2548100

5
Не @aдає 99,999999999000000000000000000000 ДЕКІМАЛЬНО? Що технічно правильно.
Вінсент Поарьє

78

"Поплавок" у більшості середовищ - це двійковий тип з плаваючою комою. Він може точно зберігати значення base-2 (до певної точки), але не може точно зберігати багато базових-10 (десяткових) значень. Поплавці найбільш підходять для наукових розрахунків. Вони не підходять для більшості бізнес-орієнтованої математики, і неналежне використання поплавців укусить вас. Багато десяткових значень не можуть бути точно представлені в base-2. 0.1Наприклад, не може, і тому ви бачите дивні результати на кшталт 1.0 - 0.1 = 0.8999999.

Десяткові знаки зберігають номери-10. Десяткові знаки - це хороший тип для більшості математики бізнесу (але будь-який вбудований тип "гроші" є більш підходящим для фінансових розрахунків), коли діапазон значень перевищує той, який надається цілими типами, і потрібні дробові значення. Десяткові знаки, як випливає з назви, розраховані на базові числа 10 - вони можуть точно зберігати десяткові значення (знову ж таки, до певної точки).


@Michael Petrotta - користувач просто вводить свої десяткові числа у поле, вказане у формах .. Мені потрібно просто зберігати їх у БД. який буде більш підходящим. ?
Хакер

12
@Pradeep: Я відчуваю, що ти не відповідаєш на мої запитання. Це може бути тому, що ви самі не знаєте відповідей - можливо, вам не комфортно запитати менеджера чи замовника про детальнішу інформацію. Якщо це так, я пропоную покусати кулю, посидіти з ними пару годин і по-справжньому пройтися по вашій заяві. Для чого саме та дуже детально використовуються ваші дані?
Майкл Петротта

1
Насправді в даний час і float, і DECIMAL зберігають свої номери однаково. Різниця полягає в тому, як ці числа використовуються. DECIMAL використовує всі біти, щоб містити ціле число доповнення двох з десятковою комою. Поплавок має два цілі числа, а одне піднімає друге на потужність. І база, і експонент є двома цілими комплементами.
користувач2548100

1
Я думаю, що ваша відповідь може бути технічно правильною, але наголос на тому, що флоат є двійковим типом, затьмарює те, що вони обидва зберігають свої дані в одному форматі. Число з плаваючою комою, підняте на першу потужність, є цілим числом і зберігається саме таким чином. Насправді для 80-бітового точного поплавця основою є int64. І навпаки, якщо ви написали бібліотеку для цілих чисел, які підняли їх до повноважень, ви зіткнулися б з тими ж проблемами з цілими числами, або DECIMALS, або римськими числами, або льодяниками. Це не помилка, яка створює "помилки округлення", це обробка математики бібліотекою.
user2548100

1
Зважаючи на дуже низьку якість запитання, де практично не наводяться параметри, які б вказували на те, що викликають занепокоєння в рамках ОП, важко знати, який відповідь є відповідним. Як правило, DECIMAL зберігатиме велику кількість, а математичні лайки відповідають очікуванням бухгалтера, в той час як подвійний поплавок - це менш ефективне середовище зберігання даних, яке значно оптимізує математичні вкладки, які набагато краще відповідають очікуванням науковців та фінансів (а не бухгалтерів).
користувач2548100

21

MySQL нещодавно змінив спосіб зберігання типу DECIMAL . Раніше вони зберігали символи (або нюбіли) для кожної цифри, що містять ASCII (або nybble) подання числа - vs - ціле число доповнення двох або деякої його похідної.

Поточний формат зберігання для DECIMAL - це серія 1,2,3 або 4-байтових цілих чисел, біти яких об'єднані, щоб створити номер доповнення двох з десятковою комою, що визначається вами, і зберігається у схемі БД під час декларації стовпця та вкажіть його розмір ДЕКІМАЛЬНО та десяткове місце.

Наприклад, якщо ви взяли 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-розрядних ніблів: 72 біт

Як 2 32-бітні цілі числа: 64 біт

В даний час DECIMAL підтримує максимум 65 цифр, як DECIMAL (M, D), де найбільше значення для M дозволене - 65, а найбільше значення D дозволене - 30.

Щоб не вимагати відрізків з 9 цифр одночасно, цілі числа, менші за 32 біти, використовуються для додавання цифр, використовуючи 1,2 та 3 байтові цілі числа. З якоїсь причини, яка не відповідає логіці, використовувались підписані замість непідписані вставки, і при цьому 1 біт викидається, що призводить до наступних можливостей зберігання. Для 1,2 та 4 байтових int втрачений біт не має значення, але для 3-байтового int це катастрофа, оскільки ціла цифра втрачається через втрату цього єдиного біта.

Із 7-бітовою вкладкою: 0 - 99

Із 15-бітовим int: 0 - 9,999

З 23-розрядним int: 0 - 999,999 (0 - 9,999,999 з 24-бітовим int)

1,2,3 і 4-байтові цілі числа об'єднуються разом, щоб утворювати "бітовий пул", який DECIMAL використовує для представлення числа точно як ціле число комплементу двох. Десяткова крапка НЕ ​​зберігається, вона мається на увазі.

Це означає, що не потрібно перетворювати ASCII в int перетворення двигуна БД, щоб перетворити "число" в те, що ЦП визнає числом. Ні округлення, ні помилок конверсії, це справжнє число, яким може управляти процесор.

Розрахунки на це довільно велике ціле число потрібно робити в програмному забезпеченні, оскільки немає апаратної підтримки для такого типу чисел, але ці бібліотеки дуже старі та високооптимізовані, написані 50 років тому для підтримки даних IBM 370 Fortran довільної точності з плаваючою точкою . Вони все ще набагато повільніше, ніж ціла ціла алгебра фіксованого розміру, зроблена з апаратним забезпеченням цілого числа процесора, або обчислення з плаваючою комою, зроблені на FPU.

З точки зору ефективності зберігання, оскільки показник поплавця приєднаний до кожного поплавця, неявно вказуючи, де знаходиться десяткова крапка, він є масовим надмірним, а отже, неефективним для роботи з БД. У БД ви вже знаєте, де десяткова крапка повинна переходити попереду, і кожен рядок таблиці, який має значення для стовпця ДЕКІМАЛЬНО, повинен лише переглянути 1 та єдину специфікацію, де потрібно розміщувати та зберігати десяткову точку. у схемі як аргументи до DECIMAL (M, D) як імплікації значень M та D.

Тут знайдено безліч зауважень щодо того, який формат слід використовувати для різних програм, тому я не буду терпіти суть. Я зайняв час, щоб написати це тут, тому що той, хто підтримує пов’язану онлайн-документацію MySQL, не розуміє жодного з перерахованих вище, і після раундів все більш неприємних спроб пояснити це я відмовився. Хорошим свідченням того, наскільки погано вони зрозуміли, що вони пишуть, є дуже заплутане і майже нерозбірливе викладення теми.

На завершення, якщо вам потрібні високоточні обчислення плаваючої точки, за останні 20 років було досягнуто величезного прогресу в коді з плаваючою точкою, а апаратне забезпечення для 96-бітового і чотириразового точності поплавця знаходиться прямо за кутом, але там є хороші бібліотеки довільної точності, якщо важливо маніпулювати збереженим значенням.


Я вважаю, що в архітектурі Hazwell Intel є операції AVX-2 на 256-бітних цілих числах, що охоплюють усі можливі значення, які можуть представляти 77 цифр, які можуть бути використані для прямої роботи над розширеними цілими числами DECIMAL. Oracle може виявитись доцільним підтримувати нову форму DECIMAL в майбутньому, що охоплює 77 цифр проти 65. Я б оцінив покращення продуктивності в 5-10 разів, використовуючи апаратне забезпечення замість програмного забезпечення. 2 ^ 256 = 115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129, 639,936 (78 цифр)

Зараз векторні процесори Intel підтримують 512 бітові математичні операції. Це охопить 154 цифри. 2 ^ 512 = 13,407,807,929,942,597,099,574,024,998,205,846,127,479,365,820,592,393,377,723,561,443,721,764,030,073,546,976,801,874,298,166,903,427,690,031,858,186,486,050,853,753,882,811,946,569,946,433,649,006,084,096 (155 цифр)

13

Не тільки специфічна для MySQL, різниця між float і десятковими типами полягає в тому, як вони представляють дробові значення. Типи з плаваючою комою представляють дроби у двійковій формі, які можуть представляти лише значення як {m*2^n | m, n Integers}. такі значення, як 1/5, неможливо точно представити (без помилки округлення). Десяткові цифри аналогічно обмежені, але представляють числа як {m*10^n | m, n Integers}. Десяткові знаки все ще не можуть представляти числа, як 1/3, але часто трапляється у багатьох загальних сферах, як, наприклад, фінанси, очікується, що певні десяткові дроби завжди можуть бути виражені без втрати вірності. Оскільки десяткове число може представляти таке значення, як $0.20(п'ята частина долара), то в цих ситуаціях він є кращим.


Оскільки процесори Intel виконують всі проміжні операції з подвійним поплавком з 80-бітовою точністю, майже без винятку немає помилки округлення, коли кінцевий результат зменшується від 80 біт до 64 біт. Навіть багато бібліотек програмного забезпечення з плаваючою комою можуть вирішувати ці та сотні інших арифметичних аномалій. Таким чином, теорія та практика дико розходяться в цій галузі.

9

десяткова призначена для фіксованих кількостей, таких як гроші, де потрібно певну кількість знаків після коми. Поплавці призначені для зберігання ... точних чисел з плаваючою комою.


6

Я вважаю це корисним:

Як правило, величини з плаваючою величиною корисні для наукових розрахунків, але не повинні використовуватися для фінансових / грошових цінностей. Для бізнес-орієнтованої математики завжди використовуйте Десяткові.

Джерело: http://code.rohitink.com/2013/06/12/mysql-integer-float-decimal-data-types-differences/


5
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)

2

Якщо ви працюєте після продуктивності, а не точності, слід зауважити, що обчислення з поплавками набагато швидше, ніж десяткові


2

Типи з плаваючою комою (приблизне значення) - FLOAT, DOUBLE

Типи FLOAT та DOUBLE представляють приблизні числові значення. MySQL використовує чотири байти для значень одноточності та вісім байтів для значень подвійної точності.

Для FLOAT стандарт SQL дозволяє необов'язково специфікувати точність (але не діапазон показника) у бітах після ключового слова FLOAT у дужках. MySQL також підтримує цю необов'язкову специфікацію точності, але значення точності використовується лише для визначення розміру пам’яті. Точність від 0 до 23 призводить до 4-байтної одноточної колонки FLOAT. Точність від 24 до 53 призводить до 8-байтної колонки з подвійною точністю DOUBLE.

MySQL дозволяє нестандартний синтаксис: FLOAT (M, D) або REAL (M, D) або ДВОЙНИЙ ТОЧНИК (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/uk/floating-point-types.html

Проблеми зі значеннями з плаваючою комою

Числа з плаваючою комою іноді викликають плутанину, оскільки вони є приблизними і не зберігаються як точні значення . Значення з плаваючою комою, записане в операторі SQL, не може бути таким же, як значення, представлене внутрішньо. Спроби трактувати значення з плаваючою комою як точні при порівнянні можуть призвести до проблем. Вони також залежать від залежностей платформи чи реалізації. Цим питанням підлягають типи даних FLOAT та DOUBLE. Для стовпців DECIMAL MySQL виконує операції з точністю до 65 десяткових цифр, що повинно вирішити найпоширеніші проблеми неточності.

У наступному прикладі використовується 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/uk/problems-with-float.html


0

Жорстке і швидке правило

Якщо все, що вам потрібно зробити, це додавати, віднімати чи множувати числа, які ви зберігаєте, найкраще DECIMAL.

Якщо вам потрібно розділити або зробити будь-яку іншу форму арифметики чи алгебри за даними, ви майже напевно будете щасливішими з поплавком. Бібліотеки з плаваючою комою та на процесорах Intel, сам процесор з плаваючою точкою, мають TON-операції з виправлення, виправлення, виявлення та оброблення пухир винятків, які трапляються при виконанні типових математичних функцій - особливо трансцендентальних функцій.

Щодо точності, я одного разу написав бюджетну систему, яка обчислювала відсотковий внесок кожного з 3000+ рахунків, для 3600 бюджетних одиниць, за місяць до вузла консолідації цієї одиниці, а потім виходячи з цієї матриці відсотків (3 000 + х 12 х 3600) Я помножив суму бюджету на найвищі організаційні вузли до наступних 3 рівнів організаційних вузлів, а потім обчислив усі (3000 + 12) значення для всіх 3200 одиниць деталізації з цього. Мільйони та мільйони та мільйони подвійних точних обчислень з плаваючою точкою, будь-який з яких би скинув згортання всіх цих проекцій під час консолідації знизу до найвищого рівня в організації.

Загальна помилка з плаваючою комою після всіх цих обчислень становила ZERO . Це було в 1986 році, і сьогодні бібліотеки з плаваючою комою набагато, набагато краще, ніж тоді. Intel робить все це проміжні обчислення подвоєнь з 80-бітовою точністю, що все, крім усунення помилки округлення. Коли хтось каже вам "це помилка з плаваючою комою", це майже впевненість НЕ правда.


-2

floatdouble) являє собою двійкові дроби

decimal являє десяткові дроби


-2
declare @float as float(10)
declare @Decimal as decimal(10)
declare @Inetger as int

set @float =10.7
set @Decimal =10.7
set @Inetger=@Decimal

print @Inetger

у float, коли встановлено значення для цілого друку 10, але у десятковій цифрі 11

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.