Питання Відмінність між десятковим, плаваючим і подвійним у .NET?


Яка різниця між decimal, float і double в .NET?

Коли б хтось користувався одним із них?


1776
2018-03-06 11:31


походження


цікава стаття zetcode.com/lang/csharp/datatypes - GibboK
@Баргітта, це неправда, є float в .NET. Просто System тип (тобто не ключове слово) називається Single. - Balázs
Пов'язані: sandbox.mc.edu/~bennet/cs110/flt/dtof.html - Pacerier


Відповіді:


float і double є плаваюча бінарний типові типи. Іншими словами, вони представляють такий номер:

10001.10010110011

Бінарне число та місце розташування бінарної точки кодуються в межах значення.

decimal це плаваюча десятковий знак точка типу. Іншими словами, вони представляють такий номер:

12345.65789

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

Важливо відзначити, що люди використовують для представлення не цілих чисел у десятковій формі і очікують точних результатів у десяткових представленнях; не всі десяткові числа точно можуть бути представлені в бінарній системі з плаваючою точкою - наприклад, 0,1, отже, якщо ви використовуєте значення бінарної функції з плаваючою комою, ви насправді отримуєте наближення до 0,1. Ви все одно отримаєте наближення, використовуючи також плаваючу десяткову точку - результат розділення від 1 до 3 не може точно бути представленим, наприклад.

Що стосується того, що використовувати, коли:

  • Для значень, які є "природними точними десятками", це добре використовувати decimal. Це, як правило, підходить для будь-яких понять, винайдених людьми: найважливішим прикладом є фінансові цінності, але є і інші. Розглянемо рахунок, який надається даймерам або льодовикам, наприклад.

  • Для цінностей, які є більш артефактами природи, які реально не можна виміряти точно все одно float/double є більш доцільними. Наприклад, наукові дані, як правило, будуть представлені у цій формі. Тут початкові значення не будуть "віддалено точні", щоб почати, тому для очікуваних результатів не важливо зберегти "десяткову точність". Типи плаваючих бінарних точок набагато швидше працюють, ніж десяткові числа.


1969
2018-03-06 11:56



float/double зазвичай не представляють числа як 101.101110, як правило, він представляється як щось подібне 1101010 * 2^(01010010) - показник - Mingwei Samuel
@Hazzard: Ось що означає "і місце розташування бінарної точки" в частині відповіді. - Jon Skeet
Я здивований, що це вже не було сказано float є ключовим словом псевдоніма C # і не є .Net-типом. його System.Single.. single і double є плаваючими типами бінарних точок. - Brett Caswell
чекати .... не десяткове представлено в 1s та 0s в кінці кінців? Я думав, що комп'ютери можуть працювати тільки в бінарній формі. так що тоді десяткове значення в кінцевому підсумку є бінарним типом? - BKSpurgeon
@ BKSpurgeon: Ну, тільки так само, як ви можете це сказати все є бінарним типом, і тоді він стає досить марним визначенням. Декільниця - це десятковий тип, оскільки це число, представлене як ціле значення та масштаб, такий, що результат є значним і * 10 ^ масштабом, а плаваюча та подвійна - важливі і * 2 ^ шкала. Ви берете число, написане в десятковій формі, і достатньо повільно перемістіть десяткову точку праворуч, щоб у вас було ціле число, щоб визначити значення та масштаб. Для плаваючого / подвійного ви починаєте з числа, написаного в двійковій системі. - Jon Skeet


Точність - головна відмінність.

Плавати - 7 цифр (32 біт)

Подвійне-15-16 цифр (64 біт)

Десятковий -28-29 значущих цифр (128 біт)

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

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

float flt = 1F/3;
double dbl = 1D/3;
decimal dcm = 1M/3;
Console.WriteLine("float: {0} double: {1} decimal: {2}", flt, dbl, dcm);

Результат:

float: 0.3333333  
double: 0.333333333333333  
decimal: 0.3333333333333333333333333333

896
2018-03-06 11:33



@Thecrocodilehunter: вибачте, але ні. Десяткове число може представляти всі числа, які можуть бути представлені в десятковій формі, але не 1/3, наприклад. 1,0 м / 3,0 м оцінюється до 0,333333333 ... з великою, але кінцевою кількістю 3-х років наприкінці. Помножте його на 3 не поверне точний 1.0. - Erik P.
@Thecrocodilehunter: Я думаю, ви заплутали точність і точність. У цьому контексті вони різні речі. Точність - це кількість цифр для представлення числа. Чим точніше, тим менше потрібно обійти. Ніякий тип даних не має нескінченної точності. - Igby Largeman
@ Thecrocodilehunter: Ви припускаєте, що вартість вимірюється точно  0.1 - це рідко буває в реальному світі! Будь-який Формат кінцевого запам'ятовує конфлікт нескінченної кількості можливих значень до кінцевого числа бітових візерунків. Наприклад, float буде конфлікт 0.1 і 0.1 + 1e-8, поки decimal буде конфлікт 0.1 і 0.1 + 1e-29. Звичайно, в межах заданого діапазону, певні значення можуть бути представлені в будь-якому форматі з нульовою втратою точності (наприклад, float може зберігати будь-яке ціле число до 1,6 ед з нульовою втратою точності) - але це все одно не так нескінченний точність - Daniel Pryden
@Thecrocodilehunter: Ви пропустили мою точку. 0.1 є не особливе значення! Єдине, що робить 0.1 "краще ніж 0.10000001 це тому, що людські істоти люблять базу 10. І навіть з a float значення, якщо ви ініціалізуєте два значення з 0.1 так само, вони будуть обидва однакові. Просто це значення не буде точно  0.1 -- це буде найближче значення до 0.1 що може бути точно представлено як a float. Звичайно, з двійковими поплавками (1.0 / 10) * 10 != 1.0, але з десятковими поплавками, (1.0 / 3) * 3 != 1.0 або Ні є чудово точний - Daniel Pryden
@Thecrocodilehunter: Ви все ще не розумієте. Я не знаю, як це якомога більше сказати: у С, якщо ти це зробиш double a = 0.1; double b = 0.1; потім a == b  буде правдою. Це просто так a і b воля обидва не зовсім рівний 0.1. У C #, якщо ви робите це decimal a = 1.0m / 3.0m; decimal b = 1.0m / 3.0m; потім a == b також буде правдою. Але в такому випадку ні від a ні b воля точно рівний 1/3 - вони будуть обидва рівні 0.3333.... В обидва випадків, деяка точність втрачається через представлення. Ви твердо говорите це decimal має "нескінченну" точність, яка є помилковий. - Daniel Pryden


Десяткова структура суворо спрямована на фінансові розрахунки, що вимагають точності, які відносно непереносимі для округлення. Декілька слів не є достатніми для наукових застосувань, однак з кількох причин:

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

66
2018-04-13 13:55



Якщо ви проводите фінансові розрахунки, вам обов'язково потрібно завантажувати власні типи даних або знайти хорошу бібліотеку, яка відповідає вашим конкретним потребам. Точність у фінансовій установці визначається органами (людьми) стандартів, і вони мають дуже специфічні локалізовані (як у часі, так і за географією) правила щодо того, як робити розрахунки. Речі, як правильне округлення, не фіксуються в простих числових типів даних у .Net. Можливість робити розрахунки - це лише дуже маленька частина головоломки. - James Moore


enter image description here

для отримання додаткової інформації ви можете перейти до джерела цієї фотографії:

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/921a8ffc-9829-4145-bdc9-a96c1ec174a5


54
2018-06-07 12:50



-1 для ствердження, що десятковий - 96 біт. MSDN чітко говорить 128. - Ben Voigt
І якщо ви копаєте глибше, це 102 біти, 128 зберігаються. Ніяким чином не вписати це в 12 байт. - Ben Voigt
Ви залишили найбільшу різницю, яка є базою, яка використовується для десяткового типу (десятковий знак зберігається як база 10, всі інші типи числових типів - база 2). - BrainSlugs83
Діапазони значень для одиночного та подвійного зображення не відображаються правильно в наведеному вище зображенні або у повідомленні оригінального форуму. Оскільки ми не можемо легко перевизначити текст тут, використовуйте символ каретки: одиночний має бути 10 ^ -45 і 10 ^ 38, а подвійний повинен бути 10 ^ -324 і 10 ^ 308. Крім того, MSDN має плаваючий діапазон від -3,4x10 ^ 38 до + 3,4x10 ^ 38. Пошук MSDN для System.Single і System.Double у випадку зміни посилань. Одинокий: msdn.microsoft.com/en-us/library/b1e65aza.aspx Подвійне: msdn.microsoft.com/en-us/library/678hzkk9.aspx - deegee


float 7 цифр точності

double має близько 15 цифр точності

decimal має приблизно 28 цифр точності

Якщо вам потрібна краща точність, використовуйте подвійну, а не плаваючу. У сучасних ЦПУ обидва типи даних мають майже однакову продуктивність. Єдиним вигідним використанням плаваючого полягає в тому, що вони займають менше місця. Практично важливо лише, якщо у вас є багато з них.

Я знайшов це цікаво. Що повинен знати кожен вчений-комп'ютер про арифметику з плаваючою точкою


40
2017-08-29 00:06



@RogerLipscombe: я б розглянув double у таких випадках (і в основному лише в тих випадках), коли не було цілішого типу розміром більше 32 біт, і double використовувався так, ніби це було 53-бітним цілим числом (наприклад, для зберігання цілого числа копійок або цілих кількох сотих центів). На сьогоднішній день це не дуже корисно для таких речей, але багато мов отримали можливість використовувати значення подвійної точності з плаваючою комою задовго до того, як вони отримали цілі математичні 64-бітні (або в деяких випадках навіть 32-розрядні!) Цілі числа. - supercat
Ваша відповідь означає точність - це єдина різниця між цими типами даних. Враховуючи, що арифметика з подвійною точкою з плаваючою точкою зазвичай реалізується в апаратне ППУ, продуктивність є значною різницею. Це може бути несуттєвим для деяких застосувань, але є критичним для інших. - saille
@supercat подвійний є ніколи правильно в бухгалтерських програмах. Оскільки подвійне значення може бути лише приблизними десятковими значеннями (навіть у межах власної точності). Це тому, що подвійне зберігання значень в базі-2 (двійковий) -центричний формат. - BrainSlugs83
@ BrainSlugs83: Використання типів з плаваючою комою для утримання не ціле число величини були б неправильними, однак історично було дуже часто, що мови мають типи з плаваючою точкою, які можуть точно відображати більші значення цілого числа, ніж їх цілі типи можуть представляти. Мабуть, найбільш екстремальним прикладом був Turbo-87, чиї цілі типи були обмежені до -32768 до +32767, але чиї Real Можливо, IIRC представляє значення до 1.8E + 19 з точністю одиниці. Я б подумав, що це буде набагато розумніше для застосування бухгалтерського обліку Real представляти цілий ряд копійок, ніж ... - supercat
... для того, щоб спробувати виконати багатоточні математики, використовуючи купу 16-бітних значень. Для більшості інших мов ця різниця не була такою екстремальною, але протягом тривалого часу для мов не було жодного цілого числа, що перевищувало 4е9, але double тип, що має одиницю точності до 9E15. Якщо потрібно зберігати цілі числа, більші за найбільший доступний тип цілого, використовуючи double спробує бути простішим і ефективнішим, ніж намагатися придушити багатоточні математики, особливо враховуючи те, що в той час як процесори мають вказівки для виконання 16x16-> 32 або ... - supercat


Ніхто не згадав про це

За замовчуванням, Floats (System.Single) і подвійний (System.Double) ніколи не використовуватимуть   перевірка переповнення, а Decimal (System.Decimal) завжди використовуватиметься   переповнення перевірки

я маю на увазі

decimal myNumber = decimal.MaxValue;
myNumber += 1;

кидає OverflowException.

Але це не так:

float myNumber = float.MaxValue;
myNumber += 1;

&

double myNumber = double.MaxValue;
myNumber += 1;

29
2018-01-02 13:12



float.MaxValue+1 == float.MaxValue, так як decimal.MaxValue+0.1D == decimal.MaxValue. Можливо, ви мали на увазі щось подібне float.MaxValue*2? - supercat
@supercar Але це не правда, що decimal.MaxValue + 1 == decimal.MaxValue - GorkemHalulu
@ supercar decimal.MaxValue + 0.1m == decimal.MaxValue нормально - GorkemHalulu
The System.Decimal викидає виняток незадовго до того, як стає не в змозі відрізнити цілі одиниці, але якщо заявка повинна мати справу, наприклад, доларів і центів, що може бути занадто пізно. - supercat


  1. Подвійне і плаваюче можна розділити на цілі нулі без винятку як в процесі компіляції, так і у режимі роботи.
  2. Десяткове значення не може бути розділене на ціле нульове значення. Компіляція завжди буде невдалою, якщо ви це зробите.

25
2017-07-29 07:21



Вони впевнені можуть! Вони також мають декілька "магічних" значень, таких як Infinity, Negative Infinity та NaN (не число), які роблять його дуже корисним для виявлення вертикальних ліній при обчисленні схилів ... Крім того, якщо вам потрібно вирішити, що виклик float .TryParse, double.TryParse і decimal.TryParse (щоб визначити, наприклад, чи рядок - це число), я рекомендую використовувати подвійне або плаваюче, оскільки вони будуть правильно аналізувати "Infinity", "-Infinity" та "NaN" , в той час як десятковий не буде. - BrainSlugs83
Компіляція тільки не вдається, якщо ви намагаєтесь розділити буквальне слово decimal на нуль (CS0020), і це справедливо для інтегральних літералів. Однак, якщо десяткове значення часу виконання делиться на нуль, ви отримаєте виняток, а не помилку компіляції. - Drew Noakes
@ BrainSlugs83 Тим не менш, ви можете не захотіти розібрати "Infinity" або "NaN" залежно від контексту. Схоже, хороша експлуатація для вводу користувача, якщо розробник не досить ретельно. - Winter