Разница между десятичной, плавающей и двойной в .NET? - PullRequest
1946 голосов
/ 06 марта 2009

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

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

Ответы [ 16 ]

2123 голосов
/ 06 марта 2009

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

10001.10010110011

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

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

12345.65789

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

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

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

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

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

994 голосов
/ 06 марта 2009

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

Число с плавающей запятой - 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
77 голосов
/ 13 апреля 2011

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

  • Определенная потеря точности допустима во многих научных расчетах из-за практических ограничений измеряемой физической проблемы или артефакта. Потеря точности не приемлема в финансах.
  • Десятичное число намного (намного) медленнее, чем число с плавающей запятой, и двойное для большинства операций, главным образом потому, что операции с плавающей запятой выполняются в двоичном формате, тогда как десятичное число выполняется в базе 10 (т. Е. Числа с плавающей запятой и двойные числа обрабатываются аппаратным обеспечением FPU, таким как MMX / SSE, тогда как десятичные дроби рассчитываются в программном обеспечении).
  • Десятичное число имеет недопустимо меньший диапазон значений, чем double, несмотря на то, что оно поддерживает больше цифр точности. Следовательно, десятичное число нельзя использовать для представления многих научных ценностей.
68 голосов
/ 07 июня 2013
+---------+----------------+---------+----------+---------------------------------------------+
| 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

46 голосов
/ 29 августа 2011

float 7 цифр точности

double имеет около 15 цифр точности

decimal имеет около 28 цифр точности

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

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

41 голосов
/ 22 апреля 2016

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

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

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

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

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

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

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

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

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

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

34 голосов
/ 02 января 2015

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

В настройках по умолчанию, 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;
27 голосов
/ 22 мая 2012

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

27 голосов
/ 29 июля 2010
  1. Double и float можно разделить на целое ноль без исключения как во время компиляции, так и во время выполнения.
  2. Десятичная дробь не может быть разделена на целое число ноль. Компиляция всегда будет неудачной, если вы сделаете это.
13 голосов
/ 16 апреля 2012

Это была интересная тема для меня, так как сегодня у нас только что была маленькая неприятная ошибка, связанная с тем, что 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 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 установил бы их на ноль.

Одд. Очень странно.

...