Я могу назвать три преимущества использования double
(или float
) вместо decimal
:
- Использует меньше памяти.
- Быстрее, потому что математические операции с плавающей запятой изначально поддерживаются процессорами.
- Может представлять больший диапазон чисел.
Но эти преимущества, по-видимому, применимы только к интенсивным вычислениям, таким как те, которые встречаются в программном обеспечении для моделирования. Конечно, двойные значения не следует использовать, когда требуется точность, например финансовые расчеты. Так есть ли практические причины когда-либо выбирать double
(или float
) вместо decimal
«нормальных» приложений?
Отредактировано, чтобы добавить: Спасибо за все отличные ответы, я узнал от них.
Еще один вопрос: несколько человек отметили, что двойные числа могут более точно представлять реальные числа. Когда объявят, я подумаю, что они, как правило, более точно их представляют. Но верно ли утверждение, что точность может уменьшаться (иногда значительно) при выполнении операций с плавающей запятой?
Ответы:
Я думаю, что вы суммировали преимущества довольно хорошо. Однако вы упускаете одно очко. Этот
decimal
тип более точен только при представлении базовых 10 чисел (например, тех, которые используются в валютных / финансовых расчетах). В общем,double
тип будет предлагать как минимум такую же высокую точность (кто-то поправит меня, если я ошибаюсь) и определенно большую скорость для произвольных действительных чисел. Простой вывод заключается в следующем: при выборе того, что использовать, всегда используйте,double
если вам не нужнаbase 10
точность, котораяdecimal
предлагает.Редактировать:
Что касается вашего дополнительного вопроса об уменьшении точности чисел с плавающей запятой после операций, это немного более тонкий вопрос. Действительно, точность (здесь я использую термин «взаимозаменяемо» для точности) будет постепенно уменьшаться после каждой операции. Это связано с двумя причинами:
Во всех случаях, если вы хотите сравнить два числа с плавающей запятой, которые в теории должны быть эквивалентны (но были получены с использованием различных вычислений), вам необходимо разрешить определенную степень допуска (насколько она различна, но обычно очень мала) ,
Более подробный обзор конкретных случаев, когда могут быть допущены ошибки в точности, см. В разделе «Точность» статьи Википедии . Наконец, если вы хотите серьезно углубиться (и математически) в обсуждение чисел / операций с плавающей точкой на машинном уровне, попробуйте прочитать часто цитируемую статью « Что должен знать каждый компьютерщик об арифметике с плавающей точкой» .
источник
double
. Современные компьютеры будут по-прежнему печатать правильное значение, но только потому, что они «угадывают» результат, а не потому, что оно действительно выражено правильно.Decimal
Тип имеет 93-бит точности в мантиссы, по сравнению с около 52 дляdouble
. Хотелось бы, чтобы Microsoft поддерживала 80-битный формат IEEE, даже если он должен был быть дополнен до 16 байтов; он мог бы обеспечить больший диапазонdouble
илиDecimal
гораздо лучшую скорость, чемDecimal
поддержку трансцендентных операций (например, sin (x), log (x) и т. д.), и точность, которая хотя и не так хороша, какDecimal
была бы намного лучше, чемdouble
.Вы, кажется, замечательно получаете преимущества использования типа с плавающей запятой. Я склонен проектировать десятичные дроби во всех случаях и полагаюсь на профилировщик, чтобы сообщить мне, если операции с десятичной дробью вызывают узкие места или замедления. В этих случаях я буду «понижать» до удвоения или смещения, но делаю это только внутренне, и тщательно пытаюсь управлять потерей точности, ограничивая количество значащих цифр в выполняемой математической операции.
В общем, если ваше значение является временным (не используется повторно), вы можете безопасно использовать тип с плавающей запятой. Настоящая проблема с типами с плавающей запятой заключается в следующих трех сценариях.
123456789.1 * .000000000000000987654321
)РЕДАКТИРОВАТЬ
Согласно справочной документации по десятичным знакам C # :
Итак, чтобы уточнить мое вышеупомянутое утверждение:
Я только когда-либо работал в отраслях, где десятичные дроби являются благоприятными. Если вы работаете над физическими или графическими движками, вероятно, гораздо выгоднее проектировать для типа с плавающей запятой (с плавающей или двойной).
Десятичное число не является бесконечно точным (невозможно представить бесконечную точность для нецелого в примитивном типе данных), но оно гораздо точнее, чем double:
РЕДАКТИРОВАТЬ 2
В ответ на комментарий Конрада Рудольфа , пункт № 1 (выше), безусловно, является правильным. Агрегация неточности действительно усугубляет. Посмотрите код ниже для примера:
Это выводит следующее:
Как вы можете видеть, даже если мы добавляем из одной и той же исходной константы, результаты удвоения менее точны (хотя, вероятно, будут округлены правильно), а число с плавающей точкой гораздо менее точно, до точки, где оно было уменьшено до две значащие цифры.
источник
Single: 667660.400000000000
а десятичное значение уступилоDecimal: 666666.7000000000
. Значение с плавающей точкой составляет чуть меньше одной тысячи от правильного значения.Используйте десятичные значения для базовых 10 значений, например, для финансовых расчетов, как предлагали другие.
Но двойной обычно более точен для произвольных вычисленных значений.
Например, если вы хотите рассчитать вес каждой строки в портфеле, используйте double, так как результат почти увеличится до 100%.
В следующем примере doubleResult ближе к 1, чем decimalResult:
Итак, снова на примере портфеля:
Рыночная стоимость каждой строки в портфеле является денежной величиной и, вероятно, будет лучше всего представлена в десятичном виде.
Вес каждой строки в портфеле (= рыночная стоимость / SUM (рыночная стоимость)) обычно лучше представить в двойном размере.
источник
Используйте double или float, когда вам не нужна точность, например, в написанной мной платформерной игре я использовал float для хранения скоростей игрока. Очевидно, мне здесь не нужна сверхточность, потому что в конце концов я обращаюсь к Int для рисования на экране.
источник
В некоторых учетах рассмотрите возможность использования целочисленных типов вместо или в сочетании. Например, допустим, что правила, по которым вы работаете, требуют, чтобы каждый результат вычисления переносился как минимум с 6 десятичными знаками, а окончательный результат будет округлен до ближайшей копейки.
Вычисление 1/6 от 100 долл. США дает 16,66666666666666 ..., поэтому стоимость, указанная в таблице, составит 16,666667 долл. США. И double, и decimal должны давать этот результат с точностью до 6 знаков после запятой. Однако мы можем избежать любой кумулятивной ошибки, передав результат вперед как целое число 16666667. Каждое последующее вычисление может быть выполнено с той же точностью и перенесено аналогично. Продолжая пример, я рассчитываю налог с продаж в Техасе на эту сумму (16666667 * .0825 = 1375000). Добавление двух (это короткий рабочий лист) 1666667 + 1375000 = 18041667. Перемещение десятичной точки обратно дает нам 18.041667, или 18,04 доллара.
Хотя этот короткий пример не приведет к кумулятивной ошибке с использованием двойной или десятичной дроби, довольно просто показать случаи, когда простое вычисление двойной или десятичной дроби и переноса накапливают значительную ошибку. Если правила, под которыми вы работаете, требуют ограниченного числа десятичных знаков, сохраняя каждое значение как целое число, умножая его на 10 ^ (требуется количество десятичных разрядов), а затем делите на 10 ^ (требуется количество десятичных знаков), чтобы получить фактическое Значение позволит избежать любой кумулятивной ошибки.
В ситуациях, когда доли копеек не встречаются (например, в торговых автоматах), нет никаких оснований использовать нецелые типы вообще. Просто думайте об этом, считая копейки, а не доллары. Я видел код, в котором каждое вычисление включало только целые копейки, но использование double приводило к ошибкам! Целое число только по математике устранило проблему. Так что мой нетрадиционный ответ, по возможности, воздерживаться от двойных и десятичных.
источник
Если вам нужно выполнить двоичное взаимодействие с другими языками или платформами, то вам, возможно, придется использовать float или double, которые стандартизированы.
источник
Примечание: этот пост основан на информации о возможностях десятичного типа из http://csharpindepth.com/Articles/General/Decimal.aspx и моей собственной интерпретации того, что это значит. Я предполагаю, что Double - это нормальная двойная точность IEEE.
Примечание 2: самое маленькое и самое большое в этом посте относится к величине числа.
Плюсы "десятичной".
Минусы десятичных
Мое мнение таково, что вы должны по умолчанию использовать «десятичную» для работы с деньгами и в других случаях, когда точное совпадение с человеческими расчетами очень важно, и что вы должны использовать использование double в качестве выбора по умолчанию в остальное время.
источник
Зависит от того, для чего это нужно.
Поскольку float и double являются двоичными типами данных, у вас есть некоторые сложности и ошибки в числах округлений, поэтому, например, double будет округлять от 0,1 до 0,100000001490116, double также будет округлять от 1/3 до 0,33333334326441. Проще говоря, не все действительные числа имеют точное представление в двойных типах
К счастью, C # также поддерживает так называемую десятичную арифметику с плавающей запятой, где числа представлены через десятичную систему чисел, а не двоичную систему. Таким образом, десятичная арифметика с плавающей запятой не теряет точности при хранении и обработке чисел с плавающей запятой. Это делает его чрезвычайно подходящим для расчетов, где требуется высокий уровень точности.
источник
Используйте с плавающей запятой, если вы цените производительность выше правильности
источник
Выберите тип функции вашего приложения. Если вам нужна точность, как в финансовом анализе, вы ответили на свой вопрос. Но если ваша заявка может рассчитываться с оценкой, вы в порядке с двойной.
Ваша заявка нуждается в быстром расчете или у него будет все время в мире, чтобы дать вам ответ? Это действительно зависит от типа приложения.
Графика голодная? достаточно float или double. Анализ финансовых данных, метеориты, ударяющие планету, в точности? Те должны были бы немного точности :)
источник
Десятичное число имеет более широкие байты, двойное изначально поддерживается процессором. Десятичное число - это основание-10, поэтому преобразование десятичного числа в двойное происходит при вычислении десятичного числа.
Помните, что .NET CLR поддерживает только Math.Pow (double, double). Десятичное число не поддерживается.
.NET Framework 4
источник
Двойные значения будут сериализованы в научную нотацию по умолчанию, если эта нотация короче десятичного дисплея. (например, .00000003 будет 3e-8) Десятичные значения никогда не будут сериализованы в научную нотацию. При сериализации для потребления внешней стороной, это может быть соображением.
источник