Где проблема с плавающей запятой в этом финансовом расчете C #? - PullRequest
0 голосов
/ 26 апреля 2011

Я получаю сообщение FIX для Распределения сделок, где Цена указана в центах (ZAR / 100), но комиссия указана в Rands .Эти значения представлены константами.Когда я выполняю этот расчет, commPerc1 показывает значение 0,099999999999999978, а commPerc2 показывает 0,1.Эти значения отличаются в x10, но при проверке обратного вычисления до Rands оба значения commRands1 и commRands2 показывают очень похожие значения 336,4831554 и 336,48315540000004 соответственно.

private const double Price = 5708.91;
private const double Qty = 5894;
private const double AbsComm = 336.4831554;

static void Main()
{

    double commCents = AbsComm * 100;
    double commPerc1 = commCents / (Qty * Price) * 100;
    double commRands1 = (Qty * Price) * (commPerc1 / 100) / 100;

    double commPerc2 = (AbsComm / (Qty * (Price / 100))) * 100;
    double commRands2 = (Qty * Price) * (commPerc2 / 100) / 100;
}

ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ: Я имею в виду устаревший код, в котором преобразование в десятичное будет включать несколько изменений и контроль качества, поэтому сейчас я должен принять double.

Ответы [ 7 ]

5 голосов
/ 26 апреля 2011

Не используйте double для финансовых расчетов, вместо этого используйте decimal.Числа с плавающей точкой подходят для физических, измеренных значений, где значение никогда не бывает точным.Но для финансовых расчетов вы работаете с точными значениями, вы не можете позволить себе ошибки из-за представлений с плавающей запятой.Вот для чего decimal сделано:

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

(из MSDN)

5 голосов
/ 26 апреля 2011

Проблема с плавающей запятой везде , потому что все ваших значений имеют тип double, который является типом с плавающей запятой двойной точности, а не base-10числовой тип.(Следовательно, все выполняемые вычисления являются вычислениями с плавающей точкой.)

Вместо этого вы должны объявить свои переменные decimal.Этот тип предназначен именно для финансовых расчетов.

4 голосов
/ 26 апреля 2011

Когда я запускаю этот расчет, commPerc1 показывает значение 0.099999999999999978, а commPerc2 показывает 0.1.Эти значения отличаются друг от друга на x10

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

2 голосов
/ 26 апреля 2011

Это связано с тем, как плавающие числа хранятся в памяти.Вы можете использовать decimal вместо double или float при работе с финансовыми расчетами.

1 голос
/ 26 апреля 2011

Пожалуйста, используйте десятичные числа для денежных расчетов.

Посмотрите Здесь

1 голос
/ 26 апреля 2011

0.099999999999999978 и 0.1 не отличаются в 10 раз, они почти одинаковы. Так же, как 0,999, это почти 1.

Но вы действительно должны использовать Decimal вместо Double для финансовых расчетов. Double не может точно представлять числа, подобные 0.1, тогда как Decimal может. (С другой стороны, ни один не может точно представлять 1/3).

Дополнительно Decimal имеет большую мантиссу и генерирует исключения при переполнении.

1 голос
/ 26 апреля 2011

Финансовые расчеты должны выполняться с использованием типа данных Decimal. Удваивает в памяти «приближения» указанного числа, поскольку указанное число не может быть полностью сохранено в пределах указанного распределения битов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...