У чому різниця між decimal, floatі doubleв .NET?
Коли хтось скористався б одним із них?
У чому різниця між decimal, floatі doubleв .NET?
Коли хтось скористався б одним із них?
Відповіді:
floatі doubleє плаваючими двійковими типами . Іншими словами, вони представляють таке число:
10001.10010110011
Двійкове число та розташування двійкової точки обоє кодуються у межах значення.
decimalє плаваючою десятковою точки типу . Іншими словами, вони представляють таке число:
12345.65789
Знову ж таки, число та розташування десяткової крапки кодуються у межах значення - саме це робить decimalтип плаваючої крапки замість типу фіксованої точки.
Важливо зазначити, що люди звикли представляти не цілі числа у десятковій формі і очікувати точних результатів у десяткових поданнях; не всі десяткові числа точно представлені у двійковій плаваючій точці - наприклад, 0,1 - тому, якщо ви використовуєте двійкове значення з плаваючою комою, ви отримаєте наближення до 0,1. Ви все одно отримаєте наближення і при використанні плаваючої десяткової крапки - результат поділу 1 на 3 не може бути точно представлений, наприклад.
Що ж робити, коли:
Для значень, які є "природно точними десятичниками", це добре використовувати decimal. Зазвичай це підходить для будь-яких понять, винайдених людиною: фінансові цінності є найбільш очевидним прикладом, але є й інші. Розглянемо, наприклад, оцінку, надану дайверам або фігуристам.
Для значень, які є більш артефактами природи, які реально неможливо точно виміряти , float/ doubleє більш підходящими. Наприклад, наукові дані зазвичай представлені у цій формі. Тут початкові значення не будуть "десятково точними" для початку, тому для очікуваних результатів не важливо підтримувати "десяткову точність". Типи бінарних точок з плаваючою точкою працювати набагато швидше, ніж десяткові.
float/ doubleзазвичай не представляють числа, як 101.101110правило, це представлено як щось на зразок 1101010 * 2^(01010010)- показника
floatце ключове слово з псевдонімом C # і не є .Net. це System.Single.. singleі doubleє плаваючими двозначними типами.
Точність - головна відмінність.
Float - 7 цифр (32 біт)
Подвійні -15-16 цифр (64 біт)
Десяткові -28-29 значущих цифр (128 біт)
Десяткові знаки мають значно більшу точність і зазвичай використовуються у фінансових програмах, які вимагають високого ступеня точності. Десяткові знаки значно повільніші (до 20X разів у деяких тестах), ніж подвійний / поплавковий.
Десяткові знаки і поплавці / парні порівнювання не можна порівняти без відступу, тоді як поплавці і парні можуть. Десяткові знаки також дозволяють кодувати або відмінювати нулі.
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
0.1 - що рідко трапляється в реальному світі! Будь-який кінцевий формат зберігання зв'яже нескінченну кількість можливих значень з кінцевою кількістю бітових шаблонів. Наприклад, floatconflate 0.1і 0.1 + 1e-8, поки decimalбуде conflate 0.1і 0.1 + 1e-29. Впевнені, що в заданому діапазоні певні значення можуть бути представлені у будь-якому форматі з нульовою втратою точності (наприклад, floatможна зберігати будь-яке ціле число до 1,6e7 з нульовою втратою точності) - але це все ще не безмежна точність.
0.1це не спеціальне значення ! Єдине, що робить 0.1«кращим», ніж 0.10000001це тому, що людям подобається база 10. І навіть зі floatзначенням, якщо ініціалізувати два значення 0.1однаковим чином, вони обидва будуть однаковими . Просто це значення точно не буде 0.1- воно буде найближчим до того, 0.1яке може бути точно представлено якfloat . Звичайно, з двійковими плавцями (1.0 / 10) * 10 != 1.0, але з десятковими плавцями (1.0 / 3) * 3 != 1.0також. Жоден з них не є абсолютно точним.
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/30.3333...decimal
Десяткова структура суворо орієнтована на фінансові розрахунки, що вимагають точності, що відносно нетерпимо до округлення. Десяткові знаки не є достатніми для наукових застосувань, однак з кількох причин:
+---------+----------------+---------+----------+---------------------------------------------+
| C# | .Net Framework | Signed? | Bytes | Possible Values |
| Type | (System) type | | Occupied | |
+---------+----------------+---------+----------+---------------------------------------------+
| sbyte | System.Sbyte | Yes | 1 | -128 to 127 |
| short | System.Int16 | Yes | 2 | -32768 to 32767 |
| int | System.Int32 | Yes | 4 | -2147483648 to 2147483647 |
| long | System.Int64 | Yes | 8 | -9223372036854775808 to 9223372036854775807 |
| byte | System.Byte | No | 1 | 0 to 255 |
| ushort | System.Uint16 | No | 2 | 0 to 65535 |
| uint | System.UInt32 | No | 4 | 0 to 4294967295 |
| ulong | System.Uint64 | No | 8 | 0 to 18446744073709551615 |
| float | System.Single | Yes | 4 | Approximately ±1.5 x 10-45 to ±3.4 x 1038 |
| | | | | with 7 significant figures |
| double | System.Double | Yes | 8 | Approximately ±5.0 x 10-324 to ±1.7 x 10308 |
| | | | | with 15 or 16 significant figures |
| decimal | System.Decimal | Yes | 12 | Approximately ±1.0 x 10-28 to ±7.9 x 1028 |
| | | | | with 28 or 29 significant figures |
| char | System.Char | N/A | 2 | Any Unicode character (16 bit) |
| bool | System.Boolean | N/A | 1 / 2 | true or false |
+---------+----------------+---------+----------+---------------------------------------------+
Я не повторюю багато хорошої (а також поганої) інформації, про яку вже відповіли в інших відповідях та коментарях, але я відповім на ваше подальше запитання порадою:
Коли хтось скористався б одним із них?
Використовуйте десятковий для підрахованих значень
Використовуйте float / double для вимірюваних значень
Деякі приклади:
гроші (ми рахуємо гроші чи міряємо гроші?)
відстань (чи вважаємо ми відстань чи вимірюємо відстань? *)
бали (чи вважаємо ми бали чи вимірюємо бали?)
Ми завжди рахуємо гроші і ніколи не повинні їх вимірювати. Зазвичай ми вимірюємо відстань. Ми часто підраховуємо бали.
* У деяких випадках, як я б назвав номінальну відстань , ми дійсно можемо захотіти «рахувати» відстань. Наприклад, можливо, ми маємо справу зі знаками країни, які показують відстані до міст, і ми знаємо, що ці відстані ніколи не мають більше однієї десяткової цифри (xxx.x km).
float 7 цифр точності
double має близько 15 цифр точності
decimal має близько 28 цифр точності
Якщо вам потрібна краща точність, використовуйте подвійний замість поплавця. У сучасних процесорах обидва типи даних мають майже однакову продуктивність. Єдиною користю використання float є те, що вони займають менше місця. Практично це має значення лише в тому випадку, якщо у вас їх багато.
Я виявив, що це цікаво. Що повинен знати кожен вчений-комп’ютер про арифметику з плаваючою комою
doubleналежним у бухгалтерському обліку додатків у тих випадках (і в основному лише тих випадках), коли жодного цілого типу, що перевищує 32 біти, не було, а цей doubleвикористовується як би 53-розрядний цілочисельний тип (наприклад, для утримання ціла кількість копійок, або ціла кількість сотих відсотків). В даний час для таких речей не так вже й багато, але багато мов отримали можливість використовувати значення з плаваючою комою з подвоєною точністю задовго до того, як вони отримали 64-бітну (а в деяких випадках навіть 32-бітну!) Цілочисельну математику.
RealIIRC могли представляти значення до 1,8E + 19 з точністю одиниці. Я думаю, було б набагато безпечніше, щоб облікова програма використовувала Realдля представлення цілої кількості копійок, ніж ...
doubleтип, що мав одиничну точність до 9E15. Якщо потрібно зберігати цілі числа, які перевищують найбільший доступний цілочисельний тип, використання doubleможе бути простішим та ефективнішим, ніж намагатися підробити багатоточну математику, особливо зважаючи на те, що в той час як процесори мають інструкції виконувати 16x16-> 32 або. ..
Про це ніхто не згадував
У налаштуваннях за замовчуванням 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;
float.MaxValue+1 == float.MaxValue, так само decimal.MaxValue+0.1D == decimal.MaxValue. Можливо, ви мали на увазі щось подібне float.MaxValue*2?
System.DecimalКидає виняток як раз перед його стає в змозі розрізняти цілі одиниці, але якщо програма має мати справу, наприклад , з доларами і центами, що може бути занадто пізно.
decimalна нуль (CS0020), і те саме стосується інтегральних літералів. Однак якщо десяткове значення часу виконання розділене нулем, ви отримаєте виняток, а не помилку компіляції.
Цілі числа, як було сказано, - це цілі числа. Вони не можуть зберігати точку чогось, наприклад, .7, .42 та .007. Якщо вам потрібно зберігати номери, які не є цілими числами, вам потрібна інша тип змінної. Можна використовувати подвійний або поплавковий тип. Ви налаштовуєте ці типи змінних точно так само: замість слова intвведіть doubleабо float. Подобається це:
float myFloat;
double myDouble;
( floatскорочується "плаваюча точка", і просто означає число з точкою, що знаходиться на кінці.)
Різниця між ними полягає у розмірі чисел, які вони можуть утримувати. Бо у floatвас може бути до 7 цифр. Для doubles ви можете мати до 16 цифр. Якщо точніше, ось офіційний розмір:
float: 1.5 × 10^-45 to 3.4 × 10^38
double: 5.0 × 10^-324 to 1.7 × 10^308
floatє 32-бітним числом і doubleє 64-бітним числом.
Двічі клацніть нову кнопку, щоб отримати код. Додайте до коду кнопки такі три рядки:
double myDouble;
myDouble = 0.007;
MessageBox.Show(myDouble.ToString());
Зупиніть програму та поверніться до вікна кодування. Змініть цей рядок:
myDouble = 0.007;
myDouble = 12345678.1234567;
Запустіть програму і натисніть подвійну кнопку. У вікні повідомлення правильно відображається номер. Додайте ще одне число в кінці, і C # знову закруглиться вгору або вниз. Мораль - якщо ви хочете точності, будьте уважні до округлення!
decimalнасправді зберігається у десятковому форматі (на відміну від бази 2; тому він не втрачає чи округлює цифри через перетворення між двома числовими системами); крім того, decimalне має поняття спеціальних значень, таких як NaN, -0, ∞ або -∞.
Це було цікавою темою для мене, тому що сьогодні у нас щойно помилковий помилок, щодо decimalменшої точності, ніж float.
У нашому C # коді ми зчитуємо числові значення з електронної таблиці Excel, перетворюємо їх у формат a decimal, а потім відправляємо це decimalназад в Сервіс для збереження в базу даних SQL Server .
Microsoft.Office.Interop.Excel.Range cell = …
object cellValue = cell.Value2;
if (cellValue != null)
{
decimal value = 0;
Decimal.TryParse(cellValue.ToString(), out value);
}
Тепер, майже для всіх наших значень Excel, це спрацювало чудово. Але для деяких, дуже малих значень Excel, використовуючи decimal.TryParseвтрачене значення повністю. Один з таких прикладів
cellValue = 0,00006317592
Decimal.TryParse (cellValue.ToString (), значення); // поверне 0
Рішенням, химерно, було перетворення значень Excel у doubleспочатку, а потім у decimal:
Microsoft.Office.Interop.Excel.Range cell = …
object cellValue = cell.Value2;
if (cellValue != null)
{
double valueDouble = 0;
double.TryParse(cellValue.ToString(), out valueDouble);
decimal value = (decimal) valueDouble;
…
}
Незважаючи на те, що doubleмає меншу точність, ніж а decimal, це насправді гарантувало, що невелика кількість все одно буде визнана. Чомусь double.TryParseнасправді вдалося отримати такі невеликі числа, тоді як decimal.TryParseвстановило б їх до нуля.
Незвичайно. Дуже дивно.
decimal.Parse("0.00006317592")працює - у вас щось інше відбувається. - Можливо, наукове позначення?
Для таких програм, як ігри та вбудовані системи, де пам'ять та продуктивність є критичними, плаваючий зазвичай є числовим типом вибору, оскільки він швидший і вдвічі менший. Цілими колись були зброєю вибору, але продуктивність з плаваючою комою випередила цілі числа в сучасних процесорах. Десяткові цифри прямо виходять!
Типи змінних Decimal, Double та Float відрізняються тим, що вони зберігають значення. Точність - головна відмінність, коли float - це тип даних з плаваючою точкою з одною точністю (32 біт), подвійний - тип даних з плаваючою точкою з подвійною точністю, а десяткова - це тип даних 128-бітної плаваючої точки.
Поплавок - 32 біт (7 цифр)
Подвійний - 64 біт (15-16 цифр)
Десяткові - 128 біт (28-29 значущих цифр)
Більше про ... різницю між десятковою, плаваючою та подвійною
Проблема всіх цих типів полягає в тому, що певна неточність існує і що ця проблема може виникати з невеликими десятковими числами, як у наступному прикладі
Dim fMean as Double = 1.18
Dim fDelta as Double = 0.08
Dim fLimit as Double = 1.1
If fMean - fDelta < fLimit Then
bLower = True
Else
bLower = False
End If
Запитання: Яке значення містить змінна bLower?
Відповідь: На 32-розрядній машині bLower містить ПРАВИЛЬНИЙ !!!
Якщо я заміню Double на десятковий, bLower містить FALSE, що є гарною відповіддю.
Удвічі проблема полягає в тому, що fMean-fDelta = 1.09999999999, що нижче, ніж 1,1.
Застереження: Я думаю, що така ж проблема, безумовно, може бути і для іншого числа, тому що десяткові - це лише подвійний з більшою точністю, а точність завжди є межею.
Насправді подвійний, плаваючий і десятковий відповідають БІННЯ десятковій у COBOL!
Прикро, що інші числові типи, реалізовані в COBOL, не існують у .Net. Для тих, хто не знає COBOL, в COBOL існують такі числові типи
BINARY or COMP like float or double or decimal
PACKED-DECIMAL or COMP-3 (2 digit in 1 byte)
ZONED-DECIMAL (1 digit in 1 byte)
Простими словами:
/==========================================================================================
Type Bits Have up to Approximate Range
/==========================================================================================
float 32 7 digits -3.4 × 10 ^ (38) to +3.4 × 10 ^ (38)
double 64 15-16 digits ±5.0 × 10 ^ (-324) to ±1.7 × 10 ^ (308)
decimal 128 28-29 significant digits ±7.9 x 10 ^ (28) or (1 to 10 ^ (28)
/==========================================================================================
Ви можете прочитати більше тут , Float , Double та Decimal .
Decimalпридатним для фінансових заявок, і це головний критерій, який потрібно використовувати при вирішенні між Decimalі Double. Рідко трапляється, що Doubleточності недостатньо для наукових застосувань, наприклад (і Decimalчасто непридатна для наукових застосувань через обмежений діапазон).
Основна відмінність кожного з них - точність.
floatє 32-bitчисло, doubleє 64-bitчисло і decimalє 128-bitчисло.
Десяткові 128 біт (значущі цифри 28-29) У випадку фінансових застосувань краще використовувати типи десяткових знаків, оскільки це дає високий рівень точності та легко уникнути помилок округлення. Використовуйте десятковий для нецілої математики там, де потрібна точність (наприклад, гроші та валюта)
Подвійні 64-бітні (15-16 цифр) Подвійні типи - це, мабуть, найбільш часто використовуваний тип даних для реальних значень, за винятком обробки грошей. Використовуйте подвійний для нецілої математики, де не потрібна найточніша відповідь.
Плаваючий 32 біт (7 цифр) Він використовується здебільшого у графічних бібліотеках, оскільки дуже високі вимоги до потужностей обробки, а також використовуються ситуації, які можуть зазнати помилок округлення.
Decimalsнабагато повільніше, ніж a double/float.
Decimalsі Floats/Doublesне може порівнюватися без акторів, тоді як Floatsі Doublesможе.
Decimals також дозволяють кодувати або прострочувати нулі.
Ви повинні згадати значення як:
Decimal dec = 12M/6;
Double dbl = 11D/6;
float fl = 15F/6;
і перевірити результати.
Float - 4
Double - 8
Decimal - 12