1 /* 2 * Copyright 2003-2012 Thomas Baumgart <tbaumgart@kde.org> 3 * Copyright 2017-2018 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of 8 * the License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "mymoneyfinancialcalculator.h" 20 #include "mymoneyfinancialcalculator_p.h" 21 22 #include <qglobal.h> 23 24 // ---------------------------------------------------------------------------- 25 // QT Includes 26 27 // ---------------------------------------------------------------------------- 28 // KDE Includes 29 30 // ---------------------------------------------------------------------------- 31 // Project Includes 32 33 #include "mymoneyexception.h" 34 dabs(const double x)35static inline double dabs(const double x) 36 { 37 return (x >= 0.0) ? x : -x; 38 } 39 MyMoneyFinancialCalculator()40MyMoneyFinancialCalculator::MyMoneyFinancialCalculator() : 41 d_ptr(new MyMoneyFinancialCalculatorPrivate) 42 { 43 Q_D(MyMoneyFinancialCalculator); 44 setPrec(); 45 setPF(); 46 setCF(); 47 setBep(); 48 setDisc(); 49 50 setNpp(0.0); 51 setIr(0.0); 52 setPv(0.0); 53 setPmt(0.0); 54 setFv(0.0); 55 56 // clear the mask 57 d->m_mask = 0; 58 } 59 ~MyMoneyFinancialCalculator()60MyMoneyFinancialCalculator::~MyMoneyFinancialCalculator() 61 { 62 Q_D(MyMoneyFinancialCalculator); 63 delete d; 64 } 65 setPrec(const unsigned short prec)66void MyMoneyFinancialCalculator::setPrec(const unsigned short prec) 67 { 68 Q_D(MyMoneyFinancialCalculator); 69 d->m_prec = prec; 70 } 71 setPF(const unsigned short PF)72void MyMoneyFinancialCalculator::setPF(const unsigned short PF) 73 { 74 Q_D(MyMoneyFinancialCalculator); 75 d->m_PF = PF; 76 } 77 setCF(const unsigned short CF)78void MyMoneyFinancialCalculator::setCF(const unsigned short CF) 79 { 80 Q_D(MyMoneyFinancialCalculator); 81 d->m_CF = CF; 82 } 83 setBep(const bool bep)84void MyMoneyFinancialCalculator::setBep(const bool bep) 85 { 86 Q_D(MyMoneyFinancialCalculator); 87 d->m_bep = bep; 88 } 89 setDisc(const bool disc)90void MyMoneyFinancialCalculator::setDisc(const bool disc) 91 { 92 Q_D(MyMoneyFinancialCalculator); 93 d->m_disc = disc; 94 } 95 setIr(const double ir)96void MyMoneyFinancialCalculator::setIr(const double ir) 97 { 98 Q_D(MyMoneyFinancialCalculator); 99 d->m_ir = ir; 100 d->m_mask |= IR_SET; 101 } 102 ir() const103double MyMoneyFinancialCalculator::ir() const 104 { 105 Q_D(const MyMoneyFinancialCalculator); 106 return d->m_ir; 107 } 108 setPv(const double pv)109void MyMoneyFinancialCalculator::setPv(const double pv) 110 { 111 Q_D(MyMoneyFinancialCalculator); 112 d->m_pv = pv; 113 d->m_mask |= PV_SET; 114 } 115 pv() const116double MyMoneyFinancialCalculator::pv() const 117 { 118 Q_D(const MyMoneyFinancialCalculator); 119 return d->m_pv; 120 } 121 setPmt(const double pmt)122void MyMoneyFinancialCalculator::setPmt(const double pmt) 123 { 124 Q_D(MyMoneyFinancialCalculator); 125 d->m_pmt = pmt; 126 d->m_mask |= PMT_SET; 127 } 128 pmt() const129double MyMoneyFinancialCalculator::pmt() const 130 { 131 Q_D(const MyMoneyFinancialCalculator); 132 return d->m_pmt; 133 } 134 setNpp(const double npp)135void MyMoneyFinancialCalculator::setNpp(const double npp) 136 { 137 Q_D(MyMoneyFinancialCalculator); 138 d->m_npp = npp; 139 d->m_mask |= NPP_SET; 140 } 141 npp() const142double MyMoneyFinancialCalculator::npp() const 143 { 144 Q_D(const MyMoneyFinancialCalculator); 145 return d->m_npp; 146 } 147 setFv(const double fv)148void MyMoneyFinancialCalculator::setFv(const double fv) 149 { 150 Q_D(MyMoneyFinancialCalculator); 151 d->m_fv = fv; 152 d->m_mask |= FV_SET; 153 } 154 fv() const155double MyMoneyFinancialCalculator::fv() const 156 { 157 Q_D(const MyMoneyFinancialCalculator); 158 return d->m_fv; 159 } 160 numPayments()161double MyMoneyFinancialCalculator::numPayments() 162 { 163 Q_D(MyMoneyFinancialCalculator); 164 const unsigned short mask = PV_SET | IR_SET | PMT_SET | FV_SET; 165 166 if ((d->m_mask & mask) != mask) 167 throw MYMONEYEXCEPTION_CSTRING("Not all parameters set for calculation of numPayments"); 168 169 double eint = d->eff_int(); 170 171 //add exception for zero interest 172 if (eint == 0.0) { 173 d->m_npp = -(d->m_pv / d->m_pmt); 174 175 } else { 176 double CC = d->_Cx(eint); 177 178 CC = (CC - d->m_fv) / (CC + d->m_pv); 179 d->m_npp = (CC > 0.0) ? log(CC) / log(eint + 1.0) : 0.0; 180 181 d->m_mask |= NPP_SET; 182 } 183 return d->m_npp; 184 } 185 payment()186double MyMoneyFinancialCalculator::payment() 187 { 188 Q_D(MyMoneyFinancialCalculator); 189 const unsigned short mask = PV_SET | IR_SET | NPP_SET | FV_SET; 190 191 if ((d->m_mask & mask) != mask) 192 throw MYMONEYEXCEPTION_CSTRING("Not all parameters set for calculation of payment"); 193 194 double eint = d->eff_int(); 195 196 //add exception for zero interest 197 if (eint == 0.0) { 198 d->m_pmt = -(d->m_pv / d->m_npp); 199 } else { 200 double AA = d->_Ax(eint); 201 double BB = d->_Bx(eint); 202 203 d->m_pmt = -d->rnd((d->m_fv + d->m_pv * (AA + 1.0)) / (AA * BB)); 204 } 205 206 d->m_mask |= PMT_SET; 207 return d->m_pmt; 208 } 209 presentValue()210double MyMoneyFinancialCalculator::presentValue() 211 { 212 Q_D(MyMoneyFinancialCalculator); 213 const unsigned short mask = PMT_SET | IR_SET | NPP_SET | FV_SET; 214 215 if ((d->m_mask & mask) != mask) 216 throw MYMONEYEXCEPTION_CSTRING("Not all parameters set for calculation of payment"); 217 218 double eint = d->eff_int(); 219 220 //add exception for zero interest 221 if (eint == 0.0) { 222 d->m_pv = -(d->m_fv + (d->m_npp * d->m_pmt)); 223 } else { 224 double AA = d->_Ax(eint); 225 double CC = d->_Cx(eint); 226 227 d->m_pv = d->rnd(-(d->m_fv + (AA * CC)) / (AA + 1.0)); 228 229 } 230 231 d->m_mask |= PV_SET; 232 return d->m_pv; 233 } 234 futureValue()235double MyMoneyFinancialCalculator::futureValue() 236 { 237 Q_D(MyMoneyFinancialCalculator); 238 const unsigned short mask = PMT_SET | IR_SET | NPP_SET | PV_SET; 239 240 if ((d->m_mask & mask) != mask) 241 throw MYMONEYEXCEPTION_CSTRING("Not all parameters set for calculation of payment"); 242 243 double eint = d->eff_int(); 244 245 //add exception for zero interest 246 if (eint == 0.0) { 247 d->m_fv = d->rnd(-(d->m_pv + (d->m_npp * d->m_pmt))); 248 } else { 249 double AA = d->_Ax(eint); 250 double CC = d->_Cx(eint); 251 d->m_fv = d->rnd(-(d->m_pv + AA * (d->m_pv + CC))); 252 } 253 254 d->m_mask |= FV_SET; 255 return d->m_fv; 256 } 257 interestRate()258double MyMoneyFinancialCalculator::interestRate() 259 { 260 Q_D(MyMoneyFinancialCalculator); 261 double eint = 0.0; 262 double a = 0.0; 263 double dik = 0.0; 264 265 const double ratio = 1e4; 266 int ri; 267 268 if (d->m_pmt == 0.0) { 269 eint = pow((dabs(d->m_fv) / dabs(d->m_pv)), (1.0 / d->m_npp)) - 1.0; 270 } else { 271 if ((d->m_pmt * d->m_fv) < 0.0) { 272 if (d->m_pv) 273 a = -1.0; 274 else 275 a = 1.0; 276 eint = 277 dabs((d->m_fv + a * d->m_npp * d->m_pmt) / 278 (3.0 * 279 ((d->m_npp - 1.0) * (d->m_npp - 1.0) * d->m_pmt + d->m_pv - 280 d->m_fv))); 281 } else { 282 if ((d->m_pv * d->m_pmt) < 0.0) { 283 eint = dabs((d->m_npp * d->m_pmt + d->m_pv + d->m_fv) / (d->m_npp * d->m_pv)); 284 } else { 285 a = dabs(d->m_pmt / (dabs(d->m_pv) + dabs(d->m_fv))); 286 eint = a + 1.0 / (a * d->m_npp * d->m_npp * d->m_npp); 287 } 288 } 289 do { 290 try { 291 dik = d->_fi(eint) / d->_fip(eint); 292 eint -= dik; 293 } catch (const MyMoneyException &) { 294 eint = 0; 295 } 296 (void) modf(ratio *(dik / eint), &a); 297 ri = static_cast<unsigned>(a); 298 } while (ri); 299 } 300 d->m_mask |= IR_SET; 301 d->m_ir = d->rnd(d->nom_int(eint) * 100.0); 302 return d->m_ir; 303 } 304 interestDue() const305double MyMoneyFinancialCalculator::interestDue() const 306 { 307 Q_D(const MyMoneyFinancialCalculator); 308 double eint = d->eff_int(); 309 310 return (d->m_pv + (d->m_bep ? d->m_pmt : 0.0)) * eint; 311 } 312 313