Каков наилучший способ округления денежных сумм до ближайших номиналов в никель, квартал, 1 доллар, 5 долларов и т. Д.? - PullRequest
3 голосов
/ 31 марта 2012

Канада объявила, что они больше не будут чеканить копейки, и Казначейство США решительно рассматривает возможность последующего иска! Это означает, что денежные суммы должны быть округлены до ближайшего никеля, что потребует большого количества программных модификаций! .. В ломбардном бизнесе мы округляли суммы займов до ближайших 5 долларовых деноминаций, например. 50, 55, 60 .. когда расчетный кредит падает между 50 и 100 долл. США, до ближайшей номинальной стоимости 10 долл. США свыше 100 долл. США и т. Д. Это обычная практика для минимизации использования меньших купюр. Итак, каков хороший алгоритм округления до ближайшего желаемого номинала?

Могу ли я создать в SQL пользовательский тип данных для округления до n-номинала или лучше оставить десятичный (8,2) тип данных в одиночку и округлить с помощью функции?

Ответы [ 3 ]

3 голосов
/ 31 марта 2012

Предполагая, что ваши числа будут выглядеть примерно так: 44.32, тогда все, что вам нужно сделать (это псевдокод, реализация в c ++ должна быть тривиальной):

findmod = (num_to_be_changed*100)%5
if findmod <= 2
  new_num = num_to_be_changed - findmod
else 
  new_num = num_to_be_changed +  (5 - findmod)
end
new_num = new_num/100
2 голосов
/ 03 апреля 2012

Я бы соблазнился использовать в SQL:

new_val = ROUND(old_value * 20) / 20;

А когда никель идет по центу, тогда:

new_val = ROUND(old_value * 10) / 10;

Это прекрасно работает в SQL с DECIMAL илиЧисловые значения;он также хорошо работает с SQL FLOAT и немного менее надежно с SQL SMALLFLOAT (просто потому, что SMALLFLOAT может иметь только около 6 десятичных знаков точности).Тот же самый базовый метод может использоваться в C ++, если old_value - это double (более сомнительно, если это float, по той же причине, что SQL SMALLFLOAT проблематичен).В C ++ или C вы использовали бы заголовок <cmath> или <math.h>, чтобы получить объявление для функции round() или roundf().Если вы используете ESQL / C и dec_t, то вам нужно decround(&dec_value, 0);.

В ESQL / C вы должны указать количество мест для округления, и вам придется кодироватьумножить и разделить тоже.Предполагая, что у вас есть десятичное значение dec_20 где-то, содержащее значение 20, вы напишите:

dec_t new_val;
decmul(&old_val, &dec_20, &new_val);
decround(&new_val, 0);
decdiv(&new_val, &dec_20, &new_val);

Возможно, вы проверите ошибку decmul() и decdiv();нет возвращаемого значения из decround() для проверки ошибок.Безопасно использовать один из входов в качестве выхода в последней строке.

1 голос
/ 03 апреля 2012

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

Когда в 1990-х годах Австралия прекратила использование монет с 1 и 2 центами, округление сумм осуществлялось только по кассовым операциям, и это по-прежнему так. Платежи по карте начисляются в цент. Аналогичным образом, счета за телефон и другие коммунальные услуги взимаются до цента, но округляются до ближайшего 5с, когда (и только когда) оплачиваются наличными через кассу. И, конечно, торговля акциями и обмен валюты по-прежнему рассматриваются в долях центов или копеек.

Так что, если вы можете предположить, что количество операций с наличными, округленными в меньшую сторону (заканчивающимися на 1, 2, 6 или 7c), примерно равно числу, округленному в большую сторону (3, 4, 8 или 9c), то единственным эффект состоит в том, что касса может быть на несколько центов в конце дня. На самом деле, это более вероятно, что он будет выше нескольких центов, потому что все транзакции с отдельными предметами будут округляться (например, каждая покупка за 3,99 доллара составляет 4,00 доллара в кассе).

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

...