В чем разница 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 бит)
Десятичные дроби имеют гораздо более высокую точность и обычно используются в финансовых приложениях, которые требуют высокой степени точности. Десятичные дроби намного медленнее (в некоторых тестах до 20 раз), чем double / float.
Десятичные числа и числа с плавающей запятой / удвоения нельзя сравнивать без приведения, тогда как числа с числами с плавающей запятой и числами с удвоением Десятичные дроби также допускают кодирование или конечные нули.
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
будет сопоставлять 0.1
и 0.1 + 1e-8
, пока decimal
будет сопоставлять 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 для измеренных значений
Некоторые примеры:
деньги (мы считаем деньги или измеряем деньги?)
расстояние (мы считаем расстояние или измеряем расстояние? *)
баллы (мы считаем баллы или измеряем баллы?)
Мы всегда считаем деньги и никогда не должны их измерять. Мы обычно измеряем расстояние. Мы часто подсчитываем баллы.
* В некоторых случаях, что я бы назвал номинальным расстоянием , мы действительно можем рассчитывать расстояние. Например, возможно, мы имеем дело со знаками стран, которые показывают расстояния до городов, и мы знаем, что на этих расстояниях никогда не бывает больше одной десятичной цифры (ххх.х км).
float
7 цифр точности
double
имеет около 15 цифр точности
decimal
имеет около 28 цифр точности
Если вам нужна лучшая точность, используйте double вместо float. В современных процессорах оба типа данных имеют практически одинаковую производительность. Единственное преимущество использования поплавка - они занимают меньше места. Практически имеет значение, только если у вас их много.
Я нашел это интересно. Что каждый компьютерщик должен знать об арифметике с плавающей точкой
double
правильным в приложениях учета в тех случаях (и в основном только в тех случаях), где не было доступно ни одного целочисленного типа больше 32 бит, и double
он использовался так, как если бы это был 53-битный целочисленный тип (например, для хранения). целое количество копеек или целых сотых процента). В наши дни такие вещи не слишком полезны, но многие языки получили возможность использовать значения с плавающей запятой двойной точности задолго до того, как они получили 64-битную (или в некоторых случаях даже 32-битную) целочисленную математику.
Real
IIRC мог представлять значения до 1,8E + 19 с точностью до единицы. Я думаю, что было бы гораздо разумнее использовать бухгалтерское приложение для Real
представления целого числа копеек, чем ...
double
тип с единичной точностью до 9E15. Если нужно хранить целые числа, которые больше, чем самый большой доступный целочисленный тип, использование double
будет более простым и эффективным, чем попытка выдумать математику с высокой точностью, особенно если учесть, что у процессоров есть инструкции для выполнения 16x16-> 32 или. ..
Никто не упомянул, что
В настройках по умолчанию Floats (System.Single) и double (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), и то же самое верно для целочисленных литералов. Однако, если десятичное значение времени выполнения делится на ноль, вы получите исключение, а не ошибку компиляции.
Целые числа, как уже упоминалось, являются целыми числами. Они не могут хранить что-то, например, 0,7, 42 и 0,007. Если вам нужно хранить числа, которые не являются целыми числами, вам нужен другой тип переменной. Вы можете использовать тип double или тип float. Вы устанавливаете эти типы переменных точно таким же образом: вместо использования слова 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
имеет меньшую точность, чем a decimal
, это фактически гарантировало, что небольшие числа все равно будут распознаваться. По какой-то причине double.TryParse
удалось действительно получить такие небольшие числа, тогда как decimal.TryParse
установил бы их на ноль.
Странный. Очень странно.
decimal.Parse("0.00006317592")
работает - у тебя что-то еще происходит. - Возможно, научная запись?
Для приложений, таких как игры и встроенные системы, где память и производительность имеют решающее значение, float обычно является числовым типом выбора, так как он быстрее и вдвое меньше двойного. Раньше целое число было оружием выбора, но производительность с плавающей запятой превысила целое число в современных процессорах. Десятичный прямо сейчас!
Переменные типа Decimal, Double и Float отличаются тем, как они хранят значения. Точность является основным отличием, когда float - это тип данных с плавающей запятой одинарной точности (32 бита), double - тип данных с плавающей запятой двойной точности (64 бита), а decimal - тип данных 128-битной плавающей запятой.
Float - 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 содержит TRUE !!!
Если я заменю Double на Decimal, bLower содержит FALSE, что является хорошим ответом.
В двойном, проблема в том, что fMean-fDelta = 1.09999999999, что ниже, чем 1.1.
Предостережение: я думаю, что та же самая проблема, безусловно, может существовать для другого числа, потому что десятичная дробь - это только двойное число с более высокой точностью, а точность всегда имеет предел.
Фактически, Double, Float и Decimal соответствуют двоичному десятичному числу в 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 цифр) двойные типы, вероятно, являются наиболее обычно используемым типом данных для реальных значений, за исключением обработки денег. Используйте double для нецелочисленной математики, где не требуется самый точный ответ.
32-разрядное число с плавающей запятой (7 цифр). Используется главным образом в графических библиотеках, поскольку очень высоки требования к вычислительной мощности, а также используются ситуации, которые могут выдержать ошибки округления.
Decimals
намного медленнее, чем 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