File indexing completed on 2024-05-12 16:42:36

0001 /*
0002     SPDX-FileCopyrightText: 2003-2012 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-FileCopyrightText: 2017-2018 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "mymoneyfinancialcalculator.h"
0008 #include "mymoneyfinancialcalculator_p.h"
0009 
0010 #include <qglobal.h>
0011 
0012 // ----------------------------------------------------------------------------
0013 // QT Includes
0014 
0015 // ----------------------------------------------------------------------------
0016 // KDE Includes
0017 
0018 // ----------------------------------------------------------------------------
0019 // Project Includes
0020 
0021 #include "mymoneyexception.h"
0022 
0023 static inline double dabs(const double x)
0024 {
0025     return (x >= 0.0) ? x : -x;
0026 }
0027 
0028 MyMoneyFinancialCalculator::MyMoneyFinancialCalculator() :
0029     d_ptr(new MyMoneyFinancialCalculatorPrivate)
0030 {
0031     Q_D(MyMoneyFinancialCalculator);
0032     setPrec();
0033     setPF();
0034     setCF();
0035     setBep();
0036     setDisc();
0037 
0038     setNpp(0.0);
0039     setIr(0.0);
0040     setPv(0.0);
0041     setPmt(0.0);
0042     setFv(0.0);
0043 
0044     // clear the mask
0045     d->m_mask = 0;
0046 }
0047 
0048 MyMoneyFinancialCalculator::~MyMoneyFinancialCalculator()
0049 {
0050     Q_D(MyMoneyFinancialCalculator);
0051     delete d;
0052 }
0053 
0054 void MyMoneyFinancialCalculator::setPrec(const unsigned short prec)
0055 {
0056     Q_D(MyMoneyFinancialCalculator);
0057     d->m_prec = prec;
0058 }
0059 
0060 void MyMoneyFinancialCalculator::setPF(const unsigned short PF)
0061 {
0062     Q_D(MyMoneyFinancialCalculator);
0063     d->m_PF = PF;
0064 }
0065 
0066 void MyMoneyFinancialCalculator::setCF(const unsigned short CF)
0067 {
0068     Q_D(MyMoneyFinancialCalculator);
0069     d->m_CF = CF;
0070 }
0071 
0072 void MyMoneyFinancialCalculator::setBep(const bool bep)
0073 {
0074     Q_D(MyMoneyFinancialCalculator);
0075     d->m_bep = bep;
0076 }
0077 
0078 void MyMoneyFinancialCalculator::setDisc(const bool disc)
0079 {
0080     Q_D(MyMoneyFinancialCalculator);
0081     d->m_disc = disc;
0082 }
0083 
0084 void MyMoneyFinancialCalculator::setIr(const double ir)
0085 {
0086     Q_D(MyMoneyFinancialCalculator);
0087     d->m_ir = ir;
0088     d->m_mask |= IR_SET;
0089 }
0090 
0091 double MyMoneyFinancialCalculator::ir() const
0092 {
0093     Q_D(const MyMoneyFinancialCalculator);
0094     return d->m_ir;
0095 }
0096 
0097 void MyMoneyFinancialCalculator::setPv(const double pv)
0098 {
0099     Q_D(MyMoneyFinancialCalculator);
0100     d->m_pv = pv;
0101     d->m_mask |= PV_SET;
0102 }
0103 
0104 double MyMoneyFinancialCalculator::pv() const
0105 {
0106     Q_D(const MyMoneyFinancialCalculator);
0107     return d->m_pv;
0108 }
0109 
0110 void MyMoneyFinancialCalculator::setPmt(const double pmt)
0111 {
0112     Q_D(MyMoneyFinancialCalculator);
0113     d->m_pmt = pmt;
0114     d->m_mask |= PMT_SET;
0115 }
0116 
0117 double MyMoneyFinancialCalculator::pmt() const
0118 {
0119     Q_D(const MyMoneyFinancialCalculator);
0120     return d->m_pmt;
0121 }
0122 
0123 void MyMoneyFinancialCalculator::setNpp(const double npp)
0124 {
0125     Q_D(MyMoneyFinancialCalculator);
0126     d->m_npp = npp;
0127     d->m_mask |= NPP_SET;
0128 }
0129 
0130 double MyMoneyFinancialCalculator::npp() const
0131 {
0132     Q_D(const MyMoneyFinancialCalculator);
0133     return d->m_npp;
0134 }
0135 
0136 void MyMoneyFinancialCalculator::setFv(const double fv)
0137 {
0138     Q_D(MyMoneyFinancialCalculator);
0139     d->m_fv = fv;
0140     d->m_mask |= FV_SET;
0141 }
0142 
0143 double MyMoneyFinancialCalculator::fv() const
0144 {
0145     Q_D(const MyMoneyFinancialCalculator);
0146     return d->m_fv;
0147 }
0148 
0149 double MyMoneyFinancialCalculator::numPayments()
0150 {
0151     Q_D(MyMoneyFinancialCalculator);
0152     const unsigned short mask = PV_SET | IR_SET | PMT_SET | FV_SET;
0153 
0154     if ((d->m_mask & mask) != mask)
0155         throw MYMONEYEXCEPTION_CSTRING("Not all parameters set for calculation of numPayments");
0156 
0157     double eint = d->eff_int();
0158 
0159     //add exception for zero interest
0160     if (eint == 0.0) {
0161         d->m_npp = -(d->m_pv / d->m_pmt);
0162 
0163     } else {
0164         double CC = d->_Cx(eint);
0165 
0166         CC = (CC - d->m_fv) / (CC + d->m_pv);
0167         d->m_npp = (CC > 0.0) ? log(CC) / log(eint + 1.0) : 0.0;
0168 
0169         d->m_mask |= NPP_SET;
0170     }
0171     return d->m_npp;
0172 }
0173 
0174 double MyMoneyFinancialCalculator::payment()
0175 {
0176     Q_D(MyMoneyFinancialCalculator);
0177     const unsigned short mask = PV_SET | IR_SET | NPP_SET | FV_SET;
0178 
0179     if ((d->m_mask & mask) != mask)
0180         throw MYMONEYEXCEPTION_CSTRING("Not all parameters set for calculation of payment");
0181 
0182     double eint = d->eff_int();
0183 
0184     //add exception for zero interest
0185     if (eint == 0.0) {
0186         d->m_pmt = -(d->m_pv / d->m_npp);
0187     } else {
0188         double AA = d->_Ax(eint);
0189         double BB = d->_Bx(eint);
0190 
0191         d->m_pmt = -d->rnd((d->m_fv + d->m_pv * (AA + 1.0)) / (AA * BB));
0192     }
0193 
0194     d->m_mask |= PMT_SET;
0195     return d->m_pmt;
0196 }
0197 
0198 double MyMoneyFinancialCalculator::presentValue()
0199 {
0200     Q_D(MyMoneyFinancialCalculator);
0201     const unsigned short mask = PMT_SET | IR_SET | NPP_SET | FV_SET;
0202 
0203     if ((d->m_mask & mask) != mask)
0204         throw MYMONEYEXCEPTION_CSTRING("Not all parameters set for calculation of payment");
0205 
0206     double eint = d->eff_int();
0207 
0208     //add exception for zero interest
0209     if (eint == 0.0) {
0210         d->m_pv = -(d->m_fv + (d->m_npp * d->m_pmt));
0211     } else {
0212         double AA = d->_Ax(eint);
0213         double CC = d->_Cx(eint);
0214 
0215         d->m_pv = d->rnd(-(d->m_fv + (AA * CC)) / (AA + 1.0));
0216 
0217     }
0218 
0219     d->m_mask |= PV_SET;
0220     return d->m_pv;
0221 }
0222 
0223 double MyMoneyFinancialCalculator::futureValue()
0224 {
0225     Q_D(MyMoneyFinancialCalculator);
0226     const unsigned short mask = PMT_SET | IR_SET | NPP_SET | PV_SET;
0227 
0228     if ((d->m_mask & mask) != mask)
0229         throw MYMONEYEXCEPTION_CSTRING("Not all parameters set for calculation of payment");
0230 
0231     double eint = d->eff_int();
0232 
0233     //add exception for zero interest
0234     if (eint == 0.0) {
0235         d->m_fv = d->rnd(-(d->m_pv + (d->m_npp * d->m_pmt)));
0236     } else {
0237         double AA = d->_Ax(eint);
0238         double CC = d->_Cx(eint);
0239         d->m_fv = d->rnd(-(d->m_pv + AA * (d->m_pv + CC)));
0240     }
0241 
0242     d->m_mask |= FV_SET;
0243     return d->m_fv;
0244 }
0245 
0246 double MyMoneyFinancialCalculator::interestRate()
0247 {
0248     Q_D(MyMoneyFinancialCalculator);
0249     double eint = 0.0;
0250     double a = 0.0;
0251     double dik = 0.0;
0252 
0253     const double ratio = 1e4;
0254     int ri;
0255 
0256     if (d->m_pmt == 0.0) {
0257         eint = pow((dabs(d->m_fv) / dabs(d->m_pv)), (1.0 / d->m_npp)) - 1.0;
0258     } else {
0259         if ((d->m_pmt * d->m_fv) < 0.0) {
0260             if (d->m_pv)
0261                 a = -1.0;
0262             else
0263                 a = 1.0;
0264             eint =
0265 
0266                 dabs((d->m_fv + a * d->m_npp * d->m_pmt) / //
0267                      (3.0 * //
0268                       ((d->m_npp - 1.0) * (d->m_npp - 1.0) * d->m_pmt + d->m_pv - //
0269                        d->m_fv)));
0270         } else {
0271             if ((d->m_pv * d->m_pmt) < 0.0) {
0272                 eint = dabs((d->m_npp * d->m_pmt + d->m_pv + d->m_fv) / (d->m_npp * d->m_pv));
0273             } else {
0274                 a = dabs(d->m_pmt / (dabs(d->m_pv) + dabs(d->m_fv)));
0275                 eint = a + 1.0 / (a * d->m_npp * d->m_npp * d->m_npp);
0276             }
0277         }
0278         do {
0279             try {
0280                 dik = d->_fi(eint) / d->_fip(eint);
0281                 eint -= dik;
0282             } catch (const MyMoneyException &) {
0283                 eint = 0;
0284             }
0285             (void) modf(ratio *(dik / eint), &a);
0286             ri = static_cast<unsigned>(a);
0287         } while (ri);
0288     }
0289     d->m_mask |= IR_SET;
0290     d->m_ir = d->rnd(d->nom_int(eint) * 100.0);
0291     return d->m_ir;
0292 }
0293 
0294 double MyMoneyFinancialCalculator::interestDue() const
0295 {
0296     Q_D(const MyMoneyFinancialCalculator);
0297     double eint = d->eff_int();
0298 
0299     return (d->m_pv + (d->m_bep ? d->m_pmt : 0.0)) * eint;
0300 }
0301