У чому різниця між 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
- що рідко трапляється в реальному світі! Будь-який кінцевий формат зберігання зв'яже нескінченну кількість можливих значень з кінцевою кількістю бітових шаблонів. Наприклад, float
conflate 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/3
0.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-бітну!) Цілочисельну математику.
Real
IIRC могли представляти значення до 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 цифр. Для double
s ви можете мати до 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