В чем разница между 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 - 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
Десятичная структура строго ориентирована на финансовые расчеты, требующие точности, которые относительно нетерпимы к округлению. Десятичные числа не подходят для научных приложений, однако по нескольким причинам:
+---------+----------------+---------+----------+---------------------------------------------+
| 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 |
+---------+----------------+---------+----------+---------------------------------------------+
Для получения дополнительной информации см.:
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/921a8ffc-9829-4145-bdc9-a96c1ec174a5
float
7 цифр точности
double
имеет около 15 цифр точности
decimal
имеет около 28 цифр точности
Если вам нужна более высокая точность, используйте double вместо float. В современных процессорах оба типа данных имеют почти такую же производительность. Единственное преимущество использования float - они занимают меньше места. Практически важно, только если у вас их много.
Я нашел это интересным. Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой
Я не буду повторять тонны хорошей (и некорректной) информации, на которую уже ответил ответ в других ответах и комментариях, но я отвечу на ваш последующий вопрос с подсказкой:
Когда кто-нибудь воспользуется одним из них?
Используйте десятичное значение для подсчитанных значений
Использовать float/double для значений измеренных
Некоторые примеры:
деньги (мы считаем деньги или измеряем деньги?)
расстояние (рассчитываем расстояние или измеряем расстояние?)
(мы подсчитываем баллы или оцениваем баллы?)
Мы всегда считаем деньги и никогда не должны их измерять. Обычно мы измеряем расстояние. Мы часто подсчитываем баллы.
* В некоторых случаях, что я бы назвал номинальным расстоянием, мы можем действительно хотеть "подсчитать" расстояние. Например, возможно, мы имеем дело со знаками страны, которые показывают расстояния до городов, и мы знаем, что эти расстояния никогда не имеют более одной десятичной цифры (xxx.x км).
Никто не упомянул, что
В настройках по умолчанию Floats (System.Single) и double (System.Double) никогда не будут использовать проверка переполнения, в то время как Decimal (System.Decimal) всегда будет использовать проверка переполнения.
Я имею в виду
decimal myNumber = decimal.MaxValue;
myNumber += 1;
throws OverflowException.
Но это не так:
float myNumber = float.MaxValue;
myNumber += 1;
&
double myNumber = double.MaxValue;
myNumber += 1;
Целые числа, как уже упоминалось, являются целыми числами. Они не могут хранить точку, например.7,.42 и.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;
Запустите программу и нажмите двойную кнопку. В поле сообщения правильно отображается номер. Добавьте еще один номер в конец, и С# снова округляется вверх или вниз. Мораль - если вы хотите точности, будьте осторожны с округлением!
Типы переменных Decimal, Double и Float отличаются тем, что они сохраняют значения. Точность - основное отличие, в котором float представляет собой тип данных с плавающей точкой с одной точностью (32 бит), double - это тип данных с плавающей точкой с двойной точностью (64 бит), а десятичный - это тип данных с плавающей точкой с 128-разрядной точкой.
Float - 32 бит (7 цифр)
Двойной - 64 бит (15-16 цифр)
Десятичный - 128 бит (28-29 значащих цифр)
Основное различие заключается в том, что Float и Doubles представляют собой двоичные типы с плавающей запятой, а Decimal будет хранить значение в виде типа с плавающей запятой. Таким образом, Decimals имеют гораздо более высокую точность и обычно используются в денежных (финансовых) или научных приложениях расчета, которые требуют высокой степени точности. Но в производительности разумные Десятичные разряды медленнее, чем двойные и плавающие типы.
Decimal может 100% точно представлять любое число в пределах точности десятичного формата, тогда как Float и Double, не могут точно представлять все числа, даже числа, которые находятся в пределах их соответствующих форматов.
Decimal
В случае финансовых приложений или научных расчетов лучше использовать десятичные типы, потому что это дает вам высокий уровень точности и легко избежать ошибок округления.
Double
Двойные типы, вероятно, являются наиболее обычно используемым типом данных для реальных значений, за исключением обработки денег.
Float
Он используется в основном в графических библиотеках, потому что очень высокие требования к мощности обработки, а также используются ситуации, которые могут выдержать ошибки округления.
Это была интересная тема для меня, так как сегодня у нас просто была неприятная небольшая ошибка, касающаяся decimal
чисел с меньшей точностью, чем float
.
В нашем коде С# мы считываем числовые значения из электронной таблицы Excel, преобразуя их в 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(), значение out); // вернет 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
установил бы их в ноль.
Странно. Очень странно.
Для приложений, таких как игры и встроенные системы, где важна память и производительность, float обычно является числовым типом выбора, поскольку он быстрее и вдвое меньше двойного. Целые были предпочтительным оружием, но производительность с плавающей запятой превосходила целое число в современных процессорах. Десятичное число прямо!
Типы переменных Decimal, Double и Float отличаются тем, что они сохраняют значения. Точность - основное отличие, в котором float представляет собой тип данных с плавающей точкой с одной точностью (32 бит), double - это тип данных с плавающей точкой с двойной точностью (64 бит), а десятичный - это тип данных с плавающей точкой с 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.
Предостережение: я думаю, что такая же проблема может существовать и для другого числа, потому что Decimal является только двойным с более высокой точностью, и точность всегда имеет предел.
Фактически, Double, Float и Decimal соответствуют BINARY десятичному значению в 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)
/==========================================================================================
You can read more here, Float, Double, and Decimal. Основное различие между каждым из них - точность.
float
- это число 32-bit
, double
- это число 64-bit
, а decimal
- число 128-bit
.
Вы также можете проверить документацию здесь:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/decimal
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/float
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/double