Лучшие практики для работы с денежными суммами в C # - PullRequest
9 голосов
/ 01 марта 2009

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

Прочитав эти статьи, каковы лучшие практики и рекомендации по работе с деньгами в C #? Должен ли я использовать определенный тип данных для небольшого количества, а другой - для большего? Кроме того, я нахожусь в Великобритании, что означает, что мы используем (например, 4000 фунтов стерлингов, тогда как другие культуры представляют одинаковое количество по-разному).

Ответы [ 7 ]

16 голосов
/ 01 марта 2009

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

Десятичное число - это числовой тип с 10-ю числами с плавающей запятой с точностью более 28 десятичных знаков. Используя Десятичное число, у вас будет меньше сюрпризов, чем с базовым типом Double 2.

Double использует вдвое меньше памяти, чем Decimal, и Double будет намного быстрее из-за аппаратного обеспечения ЦП для многих распространенных операций с плавающей запятой, но он не может точно представить большинство дробных десятичных чисел (например, 1,05) и имеет менее точный 15+. десятичные цифры точности. Double имеет преимущество большего диапазона (он может представлять большие и меньшие числа), что может пригодиться для некоторых вычислений, особенно для некоторых статистических вычислений.

В одном ответе на ваш вопрос говорится, что десятичная дробь является фиксированной точкой с 4 десятичными цифрами. Это не вариант. Если вы сомневаетесь в этом, обратите внимание, что следующая строка кода возвращает 0,0000000001:

Console.WriteLine("number={0}", 1m / 10000000000m);

Сказав все это, интересно отметить, что наиболее широко используемое в мире программное обеспечение для работы с денежными суммами, Microsoft Excel, использует двойные числа. Конечно, им приходится прыгать через много обручей, чтобы это работало хорошо, и это все еще оставляет желать лучшего. Попробуйте эти две формулы в Excel:

  • = 1-0.9-0.1
  • = (1-0.9-0.1)

Первое дает 0, второе дает ~ -2.77e-17. В некоторых случаях Excel фактически массирует числа при сложении и вычитании чисел, но не во всех.

8 голосов
/ 01 марта 2009

Вы не должны использовать числа с плавающей запятой из-за ошибок округления. Тип десятичной дроби должен подойти вам.

6 голосов
/ 01 марта 2009

Мартин Фаулер рекомендует использовать класс Money . Смотрите ссылку для обоснования. Существует множество реализаций его идеи, или вы можете написать свою собственную. Реализация Фаулера в Java, поэтому он использует класс. Версии C #, которые я видел, используют структуру, которая кажется разумной.

2 голосов
/ 01 марта 2009

Я использую объект-значение для хранения как суммы (как decimal), так и валюты. Это позволяет работать с разными валютами одновременно. decimal - рекомендуемый тип данных для денег в .NET.

0 голосов
/ 01 марта 2009

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

0 голосов
/ 01 марта 2009

Что бы вы ни делали, убедитесь, что вы понимаете, как обрабатываются валютные суммы на каждом уровне вашего приложения.

Однажды я потратил неделю на отслеживание ошибки 1 because, поскольку SQLServer и .Net используют разные способы округления валют, а приложение не согласовано в том, как оно обрабатывает определенные типы вычислений - иногда они выполнялись в SQL, иногда .сеть. Посмотрите на " банковское округление ", если вам интересно.

Есть также проблемы, связанные с форматированием валют - не уверен, что вам придется иметь дело с не британскими суммами, другими языками / культурами и т. Д., Но это добавит еще один уровень сложности.

0 голосов
/ 01 марта 2009

Я бы рекомендовал использовать десятичную дробь, как это рекомендовано другими, если требуется деление. Для простого подсчета я бы рекомендовал тип Integer. Для обоих типов я бы всегда работал на самую низкую денежную деноминацию. (т. е. центы в Канаде / США)

Мне нравится теория звонка Фаулера за деньги, добавленная @ dangph.

...