В чем разница 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-битную) целочисленную математику.
RealIIRC мог представлять значения до 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