Округление поплавков с неточным представлением - PullRequest
3 голосов
/ 25 августа 2009

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

По сути, мы хотим округлить денежные суммы, такие как 1000000000.555, до 2 десятичных знаков. Однако представление с плавающей запятой этого числа равно 1000000000.5549999, и в результате мы округлим до 1000000000.55, а не до 1000000000.56.

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

Код написан на C и должен работать на windows32 / 64 / linux / solaris, поэтому, к сожалению, у нас нет доступа к таким приятным вещам, как тип данных Decimal в .net.

Любой вклад будет полезен.

Спасибо, Рикард

Ответы [ 4 ]

10 голосов
/ 25 августа 2009

Правильный способ представления валют чаще всего использует целые числа. Например, в еврозоне общий подход заключается в представлении значений в микро-евро (1E-6). Вы, очевидно, использовали бы для этого 64-битную математику. Вы бы последовательно использовали это во всем приложении. Вы бы округлили только для человеческого ввода-вывода, и вы делали бы это путем деления на 10000, чтобы получить целое число в центах.

5 голосов
/ 25 августа 2009

Мораль этой сказки - никогда не использовать числа с плавающей запятой для обозначения денег!

Деньги поступают в виде дискретных сумм, и большинство финансовых и бухгалтерских правил признают это. Вы не можете физически оплатить счет за 3,145217 долларов. В то время как в 17-м веке было приемлемо отнести монету кузнецу и заставить его разрезать серебряный доллар на кусочки (у Pieces of Eight была хорошая маркировка кусочков пиццы, чтобы помочь этому процессу!) Сегодня это просто невозможно.

Например, самая маленькая монета, доступная в Швейцарии, стоит 5 рапсов, поэтому учет и счета должны быть выражены с точностью до 5 центов, т. Е. Вы не можете получить счет за 3,14 шв. Фр., Это должно быть 3,15 шв. Фр. Или 3,10 шв. Ваш поставщик щедр, потому что вы можете заплатить только 3,10 или 3,15 наличными.

Вы также можете открыть два варианта. Получите расширенную библиотеку BigDecimal, которая позволила бы точно указать вам округления. Или, в качестве другого автора, предложил использовать long long, представляющий ваши суммы в тысячных долях евро, и только на экране округления.

Еще одна возможность состоит в том, чтобы использовать единицы полцента, то есть 55 евро 35 центов внутренне представлены как 11070 полцентов, поэтому не нужно беспокоиться о округлении для любой стандартной бухгалтерской операции.

Я не могу не беспокоиться о том, что вы правильно не учли требования своего бизнеса. В моем последнем проекте было более ста страниц бизнес-правил, связанных с расчетами процентных ставок, по крайней мере 40 страниц касались количества десятичных знаков на каждом этапе расчета или используемого алгоритма округления.

4 голосов
/ 25 августа 2009

Я рекомендую использовать пакет десятичных чисел, например decNumber .

0 голосов
/ 25 августа 2009

Если вы находитесь в Windows и хотите написать управляемый C / C ++.

В большинстве случаев вы можете просто использовать десятичный класс . От MSDN

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

Если вы не можете или не хотите использовать управляемый C / C ++, посмотрите на пакет десятичных чисел, например decNumber .

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

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

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