В чем разница между decimal, float и double в .NET?

Когда кто-то воспользуется одним из них?

2271
Tom 6 Мар 2009 в 14:31

18 ответов

Лучший ответ

float и double - это двоичные типы с плавающей запятой.. Другими словами, они представляют собой такие числа:

10001.10010110011

Двоичное число и расположение двоичной точки закодированы внутри значения.

decimal - это плавающий десятичный тип точки. Другими словами, они представляют собой такие числа:

12345.65789

Опять же, число и расположение десятичной точки закодированы внутри значения - это то, что делает decimal по-прежнему типом с плавающей запятой, а не с фиксированной запятой.

Важно отметить, что люди привыкли представлять нецелые числа в десятичной форме и ожидать точных результатов в десятичных представлениях; не все десятичные числа точно могут быть представлены в двоичном формате с плавающей запятой - например, 0,1 - поэтому, если вы используете двоичное значение с плавающей запятой, вы фактически получите приближение к 0,1. Вы по-прежнему будете получать приближения при использовании десятичной запятой с плавающей запятой - например, результат деления 1 на 3 не может быть точно представлен.

Что использовать, когда:

  • Для значений, которые являются "естественно точными десятичными знаками", хорошо использовать decimal. Обычно это подходит для любых концепций, изобретенных людьми: наиболее очевидным примером являются финансовые ценности, но есть и другие. Рассмотрим, например, оценку, которую получают ныряльщики или фигуристы.

  • Для значений, которые представляют собой скорее артефакты природы, которые в любом случае нельзя измерить точно , более подходят float / double. Например, в этой форме обычно представлены научные данные. Здесь исходные значения не будут «десятичными точными» для начала, поэтому для ожидаемых результатов не важно поддерживать «десятичную точность». Типы с плавающей двоичной точкой работают намного быстрее, чем с десятичными.

2390
Liam 26 Янв 2018 в 16:42

Главное отличие - точность.

Float - 7 цифр (32 бит)

Double -15-16 цифр (64 бит)

Decimal -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
1130
Martin Backasch 16 Окт 2018 в 14:49
+---------+----------------+---------+----------+---------------------------------------------------------+
| C#      | .Net Framework | Signed? | Bytes    | Possible Values                                         |
| Type    | (System) type  |         | Occupied |                                                         |
+---------+----------------+---------+----------+---------------------------------------------------------+
| sbyte   | System.Sbyte   | Yes     | 1        | -128 to 127                                             |
| short   | System.Int16   | Yes     | 2        | -32,768 to 32,767                                       |
| int     | System.Int32   | Yes     | 4        | -2,147,483,648 to 2,147,483,647                         |
| long    | System.Int64   | Yes     | 8        | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
| byte    | System.Byte    | No      | 1        | 0 to 255                                                |
| ushort  | System.Uint16  | No      | 2        | 0 to 65,535                                             |
| uint    | System.UInt32  | No      | 4        | 0 to 4,294,967,295                                      |
| ulong   | System.Uint64  | No      | 8        | 0 to 18,446,744,073,709,551,615                         |
| float   | System.Single  | Yes     | 4        | Approximately ±1.5e-45 to ±3.4e38                       |
|         |                |         |          |  with ~6-9 significant figures                          |
| double  | System.Double  | Yes     | 8        | Approximately ±5.0e-324 to ±1.7e308                     |
|         |                |         |          |  with ~15-17 significant figures                        |
| decimal | System.Decimal | Yes     | 16       | Approximately ±1.0e-28 to ±7.9e28                       |
|         |                |         |          |  with 28-29 significant figures                         |
| char    | System.Char    | N/A     | 2        | Any Unicode character (16 bit)                          |
| bool    | System.Boolean | N/A     | 1 / 2    | true or false                                           |
+---------+----------------+---------+----------+---------------------------------------------------------+

Дополнительную информацию см. здесь.

95
Brady Davis 24 Дек 2020 в 01:29

Структура Decimal строго предназначена для финансовых расчетов, требующих точности, которые относительно нетерпимы к округлению. Однако десятичные дроби не подходят для научных приложений по нескольким причинам:

  • Некоторая потеря точности допустима во многих научных расчетах из-за практических ограничений измеряемой физической проблемы или артефакта. В финансах потеря точности недопустима.
  • Decimal намного (намного) медленнее, чем float и double для большинства операций, в первую очередь потому, что операции с плавающей запятой выполняются в двоичном формате, тогда как Decimal выполняется в базе 10 (т.е. с плавающей точкой и двойными числами обрабатываются аппаратным обеспечением FPU, таким как MMX / SSE , а десятичные дроби рассчитываются программно).
  • Decimal имеет недопустимо меньший диапазон значений, чем double, несмотря на то, что он поддерживает большее количество цифр точности. Следовательно, Decimal нельзя использовать для представления многих научных значений.
91
Mark Jones 13 Апр 2011 в 13:55

Я не буду повторять тонны хорошей (и некоторой плохой) информации, на которую уже были даны ответы в других ответах и ​​комментариях, но я отвечу на ваш последующий вопрос советом:

Когда кто-нибудь будет использовать один из них?

Используйте десятичные числа для подсчитанных значений

Используйте float / double для измеренных значений

Некоторые примеры:

  • деньги (мы деньги считаем или измеряем?)

  • расстояние (мы считаем расстояние или измеряем расстояние? *)

  • баллы (мы подсчитываем баллы или измеряем баллы?)

Мы всегда считаем деньги и никогда не должны их измерять. Обычно мы измеряем расстояние. Мы часто считаем баллы.

* В некоторых случаях то, что я бы назвал номинальным расстоянием , мы действительно можем захотеть «подсчитать» расстояние. Например, возможно, мы имеем дело со знаками страны, которые показывают расстояния до городов, и мы знаем, что на этих расстояниях никогда не бывает более одной десятичной цифры (xxx.x км).

65
tomosius 22 Апр 2016 в 15:18

float 7 знаков точности

double имеет около 15 знаков точности

decimal имеет около 28 знаков точности

Если вам нужна более высокая точность, используйте double вместо float. В современных процессорах оба типа данных имеют почти одинаковую производительность. Единственное преимущество использования поплавков - они занимают меньше места. Практически имеет значение, только если у вас их много.

Я нашел это интересным. Что должен знать каждый компьютерный ученый об арифметике с плавающей запятой

49
ABCD 15 Июл 2014 в 21:42

Никто не упомянул, что

В настройках по умолчанию 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;
39
GorkemHalulu 15 Апр 2015 в 13:55

Как уже упоминалось, целые числа - это целые числа. Они не могут сохранить точку, например .7, .42 и .007. Если вам нужно хранить числа, которые не являются целыми числами, вам понадобится другой тип переменной. Вы можете использовать двойной или плавающий тип. Вы устанавливаете эти типы переменных точно так же: вместо слова int вы вводите double или float. Нравится:

float myFloat;
double myDouble;

(float - это сокращение от «плавающая запятая» и означает просто число с точкой на конце.)

Разница между ними заключается в размере чисел, которые они могут вместить. Для float вы можете иметь до 7 цифр в своем номере. Для double вы можете иметь до 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 # снова округлится в большую или меньшую сторону. Мораль такова: если вам нужна точность, будьте осторожны с округлением!

28
Sae1962 19 Фев 2018 в 12:42
  1. Double и float можно без исключения разделить на целое число ноль как во время компиляции, так и во время выполнения.
  2. Десятичное число нельзя делить на целое число ноль. Компиляция всегда будет неудачной, если вы это сделаете.
26
xport 29 Июл 2010 в 07:21
  • float: от ± 1,5 x 10 ^ -45 до ± 3,4 x 10 ^ 38 (~ 7 значащих цифр
  • двойной: от ± 5,0 x 10 ^ -324 до ± 1,7 x 10 ^ 308 (15-16 значащих цифр)
  • десятичный: от ± 1,0 x 10 ^ -28 до ± 7,9 x 10 ^ 28 (28-29 значащих цифр)
17
Wai Ha Lee 2 Апр 2019 в 23:50

Это была интересная тема для меня, так как сегодня у нас только что произошла небольшая неприятная ошибка, касающаяся того, что decimal имеет меньшую точность, чем float.

В нашем коде C # мы читаем числовые значения из электронной таблицы 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 value); // вернет 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 обнулял их.

Странный. Очень странно.

11
Sae1962 19 Фев 2018 в 10:45

Для приложений, таких как игры и встроенные системы, где важны и память, и производительность, float обычно является числовым типом выбора, поскольку он быстрее и вдвое меньше double. Целые числа были предпочтительным оружием, но производительность с плавающей запятой в современных процессорах обогнала целые числа. Десятичная дробь прямо сейчас!

8
yoyo 11 Апр 2016 в 22:52

Проблема со всеми этими типами заключается в том, что существует некоторая неточность И что эта проблема может возникать с небольшими десятичными числами, как в следующем примере

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 на Decimal, bLower будет содержать FALSE, что является хорошим ответом.

В двойном случае проблема в том, что fMean-fDelta = 1.09999999999, что ниже 1.1.

Предостережение: я думаю, что такая же проблема, безусловно, может существовать для другого числа, потому что Decimal - это только double с более высокой точностью, а точность всегда имеет предел.

Фактически, 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) 
5
schlebe 23 Фев 2017 в 13:05

Простыми словами:

  1. Типы переменных Decimal, Double и Float различаются способом хранения значений.
  2. Точность - это основное отличие (обратите внимание, что это не единственное отличие), где float - это тип данных с плавающей запятой одинарной точности (32 бита). , double - это тип данных с плавающей запятой двойной точности (64 бит), а decimal - это 128-битный тип данных с плавающей запятой.
  3. Сводная таблица:
/==========================================================================================
    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)
/==========================================================================================
Вот Терка Двойной Десятичная дробь
4
GntS 10 Фев 2018 в 09:19
  • Десятичный 128 бит (28–29 значащих цифр) В случае финансовых приложений лучше использовать Десятичные типы, поскольку они обеспечивают высокий уровень точности и позволяют избежать ошибок округления. Используйте десятичную дробь для нецелочисленной математики, где требуется точность (например, деньги и валюта)

  • Double 64-бит (15–16 цифр) Двойные типы, вероятно, являются наиболее часто используемым типом данных для реальных значений, за исключением обработки денег. Используйте double для нецелочисленной математики, когда нет необходимости в наиболее точном ответе.

  • с плавающей запятой 32-бит (7 цифр) Он используется в основном в графических библиотеках, потому что очень высокие требования к вычислительной мощности, также используются ситуации, в которых могут возникать ошибки округления.

Decimals намного медленнее, чем double/float.

Decimals и Floats/Doubles нельзя сравнивать без приведения, тогда как Floats и Doubles можно.

Decimals также разрешает кодировку или завершающие нули.

3
Reza Jenabi 14 Дек 2019 в 12:16

Основное различие между ними - точность.

float - это число 32-bit, double - это число 64-bit, а decimal - это число 128-bit.

2
Imran Ali Khan 6 Июн 2015 в 08:07

Определение Decimal, Float и Double в .Net (c #)

Вы должны указать значения как:

Decimal dec = 12M/6;
Double dbl = 11D/6;
float fl = 15F/6;

И проверьте результаты.

И байты, занимаемые каждым, равны

Float - 4
Double - 8
Decimal - 12
-3
Community 20 Июн 2020 в 09:12