2009-07-22 4 views
719

Я продолжаю видеть людей, использующих удвоения в C#. Я знаю, что я где-то читал, что удваивается, иногда теряют точность. Мой вопрос в том, когда следует использовать double и когда следует использовать десятичный тип? Какой тип подходит для расчета денег? (т.е. более 100 млн. долл. США)десятичный и двойной! - Кого я должен использовать и когда?

+4

Вы хотите доли центов? (например, на бензоколонках) –

+0

http: // stackoverflow.com/questions/803225/when-should-i-use-double-than-decimal – AaronS

+1

На самом деле есть довольно ответ: decimal работает как long и int (это интегральный тип!), но у него есть точка где-то в формате синтаксиса и вывода (см. http://en.wikipedia.org/wiki/Integer_(computer_science)). Двойные и плавающие работы с мантиссой и экспонентом (см. Http://en.wikipedia.org/wiki/Floating_point). Вот и все. – atlaste

ответ

854

За деньги, всегда decimal. Вот почему он был создан.

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

Если точное значение чисел не имеет значения, используйте double для скорости. Сюда входят вычисления графики, физики или других физических наук, где уже имеется «количество значимых цифр».

+30

Это не то, что двойной неточно - он имеет * относительную * точность и может представлять очень большие или малые величины, которые десятичный не может обрабатывать вообще. –

+64

Вот почему вы используете Decimal за деньги: точность Double - всего 16 десятичных цифр, и после всего лишь нескольких арифметических операций ошибки быстро накапливаются достаточно большими, чтобы ползать в цифры 15, 14, 13 и т. Д. Округление до «центов» требует, по крайней мере, одной цифры полной точности после цифры центов, но на самом деле вам следует зарезервировать 4 или 5, чтобы изолировать от кумулятивных арифметических ошибок, которые вы НЕ МОЖЕТЕ разрешить испортить сотый столбец, который вы используете для округления центов. Это оставит вас с 16 (всего) - 2 (центов) - (4 или 5 исправлений ошибок) = oh $ ударит только 7 (или меньше) надежных целых цифр за ваши деньги! – Triynko

+15

В результате я не буду манипулировать денежными значениями более 9,99 $ (1 целая цифра), потому что вместо 4 или 5 цифр заполнения накоплений ошибок я бы хотел больше, чем 10 или 11. Поскольку Decimal - это 128- бит, это дает вам такую ​​изоляцию, даже с цифрами в сотнях триллионов долларов, потому что она имеет 28-29 цифр точности. Однако вы не можете пойти намного выше этого. 999,999,999,999,999.99R (999 трлн.) Потребует 18 цифр точности для правильного округления, а так как десятичное значение дает вам 28-29, это всего лишь 10 цифр совокупной арифметической ошибки изоляции. – Triynko

23

За деньги: decimal. Это стоит немного больше памяти, но не имеет проблем округления, например, double.

+2

у него есть все проблемы с округлением: попробуйте '1m/3m + 1m/3m == 2m/3m'. Основное различие - больше бит для значимости и, самое главное, отсутствие потери точности при работе с числами с 5 в простой факторизации делителя. Например. '1m/5m + 1m/5m' будет в точности равным' 2m/5m'. – user2622016

6

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

Вот пример в питона код:

>>> amount = float(100.00) # one hundred dollars 
>>> print amount 
100.0 
>>> new_amount = amount + 1 
>>> print new_amount 
101.0 
>>> print new_amount - amount 
>>> 1.0 

выглядит вполне нормально.

Теперь попробуйте это снова с 10^20 долларов Зимбабве

>>> amount = float(1e20) 
>>> print amount 
1e+20 
>>> new_amount = amount + 1 
>>> print new_amount 
1e+20 
>>> print new_amount-amount 
0.0 

Как вы можете видеть, что доллар исчез.

Если вы используете целочисленный тип, он отлично работает:

>>> amount = int(1e20) 
>>> print amount 
100000000000000000000 
>>> new_amount = amount + 1 
>>> print new_amount 
100000000000000000001 
>>> print new_amount - amount 
1 
+5

Вам даже не нужны очень большие/малые значения, чтобы найти различия между приближениями double2 base2 и фактические значения базы 10, многие мелкие значения не могут быть точно сохранены. Вычислите «1 - 0,1 - 0,9» (убедитесь, что компилятор не оптимизирует уравнение) и сравните его с нолем. Вы обнаружите, что с удвоением результат - это что-то вроде 2e-17 вместо 0 (убедитесь, что вы выполняете сравнение, так как многие функции print/ToString округляются до нескольких десятков раз, чтобы удалить эти типы ошибок). – David

+1

целое?! и что происходит, когда у вас есть 1,5 доллара? – Noctis

+2

@Noctis вы придумаете решение, если подумаете об этом –

32

Десятичный для точных значений. Двойной для приблизительных значений.

USD: $12,345.67 USD (Decimal) 
CAD: $13,617.27 (Decimal) 
Exchange Rate: 1.102932 (Double) 
+6

Десятичное значение не для точных значений. Decimal обеспечивает 28-29 десятичных цифр точности в соответствии с документацией. Десятичное число не выполняет аналитическую арифметику и поэтому не является «точным». Десятичная величина отлично подходит для денег, потому что даже со значениями в триллионах долларов она все равно оставляет вас с 10 цифрами изоляции от кумулятивной арифметической ошибки, при этом все еще можно точно округлить до центов. – Triynko

+2

Почему обменный курс двойной, а не десятичный? Разве это не просто цена 1 доллара США в CAD? – gerrit

+2

@gerrit Курс обмена - это не «цена» * 1 USD в CAD. Это * отношение * значения двух. В зависимости от вашего источника определяется, сколько десятичных знаков вам будет предоставлено. Например, 1 доллар США стоит 1,0016 CAD. 1 Великий британский фунт стоит 1,5909 CAD. 1 Вьетнамский Донг стоит 0,000048 CAD. Это * ratio *, так как невозможно реалистично урезать где угодно, не теряя точности. –

154

Мой вопрос, когда следует используйте дважды, и когда я должен использовать десятичную типа?

decimal, когда вы работаете со значениями в диапазоне от 10^(+/- 28) и где у вас есть ожидания относительно поведения на основе базы 10 представлений - в основном деньги.

double, когда вам нужна относительной точность (т.е. потеря точности в хвостовых цифрах на больших значениях не проблема) по дико различной величине - double охватывает более чем 10^(+/- 300). Примером здесь являются научные расчеты.

какой тип подходит для денег расчеты?

десятичное, десятичного, десятичного

Принимать нет заменителей.

Наиболее важным фактором является то, что double, реализуется в виде бинарного фракции, не может точно отражать много decimal фракций (например, 0,1) на всех и его общее количество цифр меньше, так как это 64-битный против 128-бит для decimal. Наконец, финансовые приложения часто должны следовать конкретным rounding modes (иногда это предусмотрено законом). decimalsupports these; double нет.

+2

Нет сомнений в том, что 'double' не используется при представлении финансовых значений, но что именно вы имели в виду, когда вы написали, что' double' не поддерживает определенные режимы округления по сравнению с 'decimal'? AFAIK, 'Math.Round' имеет перегрузки, которые принимают параметр' MidpointRounding' для 'double' и' decimal'? – Groo

+2

@Groo: Думаю, я, должно быть, посмотрел API .Net 1.1, этот метод был добавлен в 2.0, но он все же бесполезен из-за проблем с бинарными дробями. В текущем документе API есть пример, который иллюстрирует эту проблему. –

33

System.Single/float - 7 цифр
System.Double/double - 15-16 цифр
System.Decimal/decimal - 28-29 значащие цифры

Путь я ужаленный, используя неправильный тип (хороший несколько лет назад) это с большими объемами:

  • £ 520,532.52 - 8 цифр
  • £ 1323, 523.12 - 9 цифр

У вас заканчивается 1 миллион для поплавка.

15-значный денежная стоимость:

  • £ 1,234,567,890,123.45

9 трлн с двойным. Но с разделением и сравнением это сложнее (я определенно не эксперт в области с плавающей запятой и иррациональными номерами - see Marc's point). Смешивание десятичных и двойников вызывают вопросы:

Математической или сравнение операция , которая использует числа с плавающей точкой может не дать тот же результат, если десятичного числа используется, так как число с плавающей точкой не может точно аппроксимируют десятичное число .

When should I use double instead of decimal? имеет некоторые аналогичные и более подробные ответы.

Использование double вместо decimalдля денежных приложений является микро-оптимизация - это самый простой способ, я смотрю на него.

+1

'520,532.52' имеет 8 значащих чисел, а' 1,323,523.12' имеет 9 http://mathsfirst.massey.ac.nz/Algebra/Decimals/SigFig.htm –

 Смежные вопросы

  • Нет связанных вопросов^_^