Комментарии 20
Почти все денежные системы пришли к десятичным дробным частям (копейка = 1/100 рубля и т.п.)
При таком подходе любой INT в условных копейках — самое элементарное решение которое придется только минимально подтьюнить при вычислении процентов и делении.
Ну а в том же ORACLE и других SQL базах данных есть специальные типы под деньги. Ну собственно базы данных они как правило и хранят «деньги». А часто еще и обрабатывают.
придется только минимально подтьюнить при вычислении процентов и делении.
А вот и не минимально. Пример — инвестиции толпы с выплатой процентов. В случае лишних денег — проблемы с законом и репутацией.
Начать изучение можно с парадокса Алабамы.
А ещё есть Биткойн.
инвестиции толпы с выплатой процентов
Выплата процентов подлежит бухгалтерскому учету. Бухучет всегда оперирует минимальным квантов денег в соответствующей национальной валюте, т. е. в современной России — 1 копейка (много-много лет назад это была ¼ копейки). Следовательно, любая выплата процентов должна быть округлена до 1 копейки.
Эти проценты нужно хранить в бухгалтерском учете, наряду с копейками, также без потери точности.
Так вот там два типа данных с фиксированной точкой:
PACKED — фактически тот же FIXED DECIMAL в PL/1, BCD. Аналог в SQL — DECIMAL
и
ZONED — фактически это представление числа в виде строки. Аналог в SQL — NUMERIC
Что же касается представления сумм в миноритарных единицах, то тут ноги растут немного из другого места. Дело в том, что не во всех валютах количество миноритарных единиц в основной равно 100. Есть валюты (бельгийский франк, итальянская лира, японская йена), в которых вообще миноритарных единиц нет. А есть такие (бахрейнский динар, оманский риал, тунисский динар), где 1000 миноритарных единиц в основной.
Поэтому в банках для расчетов используются миноритарные единицы с указанием валюты, а перевод из миноритарных в основные идет по справочнику валют, где указано количество миноритарных в основной.
Но для операций с валютами всегда используется арифметика с фиксированной точкой.
В RPG еще есть функция округления %DECH
Сейчас программиста, не сталкивающегося с финансово-экономическими расчетами, легко узнать по предложению хранить все в целых копейках. Им кажется, что деньги только складывают и умножают ))
Просто в банке работаю. Пишу под AS/400 (IBM i нынче которая). Преимущественно на RPG (но и на C/C++ тоже — там, кстати, тип Decimal встроен для этой платформы, это аналог RPGшного PACKED и поддерживается он на уровне собственно системы — весь код работы с ним, я почти уверен, уже ниже уровня SLIC).
А хранится все, действительно «в копейках». Но причина там совсем другая — выше написал. Специально глянул по нашему справочнику валют — не у всех валют в «рубле» 100 «копеек». Есть и 0 (т.е. вообще нет понятия «копейка»), есть и 1000 (этих мало, но они есть).
Соответственно, чтобы понимать о чем речь, мы всегда смотрим сумму, валюту и количество миноритарных единиц для данной валюты по справочнику валют. Но это вся уже для правильного отображения суммы. А сами они хранятся, дай бог памяти, в переменных типа packed(23: 0) (могу соврать в деталях — я последнее время больше по комплаенсу работаю и ядровым функциям, а эта тема все-таки команды системы расчетов — с ними давно уже не работал)
А вообще тут про COBOL уже было. Именно про его арифметику с фиксированной точкой, правда, в разрезе скорости расходимости рекуррентного соотношения Мюллера — на фиксированной точке оно раза в два более устойчиво чем на плавающей.
«Столпы» (Клемент, Хатчинсон — который RPGPGM ведет) там тоже присутствуют и активны
У нас точно знаю что на нем сидят Альфа, Райф и Росбанк.
Мы сейчас на версии 7.3, послед НГ обещали накатить TR9 (на бой, на тестовом уже накатили), а ближе к лету — 7.4
Система очень интересная и концептуально цельная. И очень хорошо работает там, где требуется одновременная работа множества заданий.
Так что все нормально :-)
Вот не надо путать читателей, называя десятичное представление с фиксированной точкой "точным".
В тред врывается НДС 20%. Пусть отпускная цена товара 100р. Представьте, пожалуйста, цену без НДС в виде DECIMAL.
Кстати, а как в реальной жизни решают такие проблемы? Округляют до копейки? Берут в партии столько единиц товара, чтобы всё нормально поделилось?
P.S. Забавно — можно подобрать НДС так, чтобы в десятичной системе счисления получались конечные дроби. Например, 25%, 2.4% или 19.20928955078125%
Кстати, а как в реальной жизни решают такие проблемы? Округляют до копейки?
Округляют. Потому что операцию надо отразить в бухгалтерском учете, а там все операции должны быть проведены в рублях и копейках, но не долях копейки. Если введут монеты типа «½ копейки» или «¼ копейки», как это уже было, значит будут округлять то 0,5 или 0,25 копейки.
С НДС факт продажи — это вообще несколько проводок, потому что НДС учитывается отдельно. Каждую проводку тоже надо округлить до копеек.
Кстати, некоторые налоги при начислении и уплате округляют до рубля.
Забавно — можно подобрать НДС так, чтобы в десятичной системе счисления получались конечные дроби. Например, 25%, 2.4% или 19.20928955078125%
Логика НДС другая. Если Вы хотите продать товар за 100 рублей, то сверх этой суммы Вы должны взять с покупателя еще 20% (или 10%, или 0%) — налог-то с оборота берется. А в бюджет нужно заплатить разницу между тем, что Вы взяли с покупателей сверх своей цены, и тем, что Вы сами заплатили сверх цены продавца при покупке сырья.
НДС — 16,67 руб.
Итого к оплате: 100,00 руб.
Вот-вот. Всё равно где-то да вылезет округление, так что нелепо надеяться, что представление точное.
Представлять надо не точно, а как налоговая говорит :-D
Представлять надо не точно, а как налоговая говорит
А это не налоговая говорит, а Налоговый Кодекс и документы ЦБ, связанные с денежным обращением. Собственно, это не только в России так, для чего и придумали денежные типы данных для всяких баз данных — чтобы их движки сами ничего не округляли и не повышали/понижали точность представления.
К сожалению, сами названия «FIXED/FLOAT» (вместо «ТОЧНОЕ/ПРИБЛИЖЕННОЕ») не вносят ясности и интуитивно непонятны.
Они интуитивно понятны, если знать, что такое "число с фиксированной точкой" и что такое "число с плавающей точкой". А именно, это сокращения от fixed point и floating point.
Кроме того, в компьютерах все числовые типы — некие приближения к понятию числа. Ни один тип не может вместить все числа, т.к. размер памяти ограничен, и для любого типа легко найдётся число, которое невозможно представить в нём точно.
Вернемся к простейшему примеру точных вычислений, теперь на языке PL/1, добавив деление на ту же константу, чтобы вернуть исходное значение переменной. Вычисления проведем и для типа FIXED DECIMAL и для типа FLOAT(53) – аналога типа «double» в других языках.
Не стоит забывать, что тут мы можем столкнуться с потерей точности. Пример на RPG:
dcl-s fltValue float(8) inz(165.783);
dcl-s pkdValue packed(6 : 3) inz(165.783);
dcl-s zndValue zoned(6 : 3) inz(165.783);
dsply (%char(fltValue));
dsply (%char(pkdValue));
dsply (%char(zndValue));
dsply ('-------------');
fltValue *= 0.137;
pkdValue *= 0.137;
zndValue *= 0.137;
dsply (%char(fltValue));
dsply (%char(pkdValue));
dsply (%char(zndValue));
dsply ('-------------');
fltValue /= 0.137;
pkdValue /= 0.137;
zndValue /= 0.137;
dsply (%char(fltValue));
dsply (%char(pkdValue));
dsply (%char(zndValue));
Результат:
+1.657830000000000E+002
165.783
165.783
-------------
+2.271227100000000E+001
22.712
22.712
-------------
+1.657830000000000E+002
165.781
165.781
Видим расхождение в третьем знаке. Оно обусловлено тем, что после первого умножения мы теряем три знака 0.000271 — они не помещаются в переменную с фиксированными тремя знаками после запятой.
Это то, что следует иметь ввиду при работе с переменными с фиксированной точкой.
О реализации точного представления чисел или «где хранить деньги?»