summaryrefslogtreecommitdiffstats
path: root/kmymoney2/mymoney/mymoneyfinancialcalculator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmymoney2/mymoney/mymoneyfinancialcalculator.cpp')
-rw-r--r--kmymoney2/mymoney/mymoneyfinancialcalculator.cpp348
1 files changed, 348 insertions, 0 deletions
diff --git a/kmymoney2/mymoney/mymoneyfinancialcalculator.cpp b/kmymoney2/mymoney/mymoneyfinancialcalculator.cpp
new file mode 100644
index 0000000..d6686a6
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyfinancialcalculator.cpp
@@ -0,0 +1,348 @@
+/***************************************************************************
+ mymoneyfinancialcalculator.cpp - description
+ -------------------
+ begin : Tue Oct 21 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <math.h>
+#include <stdio.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+#include "mymoneyfinancialcalculator.h"
+#include "mymoneyexception.h"
+
+// #ifndef HAVE_ROUND
+// #undef roundl
+// #define roundl(a) rnd(a)
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::rnd(const FCALC_DOUBLE x) const
+{
+ FCALC_DOUBLE r,f;
+
+ if(m_prec > 0) {
+#ifdef HAVE_ROUND
+ f = powl(10.0, m_prec);
+ r = roundl(x * f)/f;
+#else
+ char buf[50];
+#if HAVE_LONG_DOUBLE
+ sprintf (buf, "%.*Lf", m_prec, x);
+ sscanf (buf, "%Lf", &r);
+#else
+ sprintf (buf, "%.*f", m_prec, x);
+ sscanf (buf, "%lf", &r);
+#endif
+#endif
+ } else
+ r = roundl(x);
+ return r;
+}
+// #endif
+
+static inline FCALC_DOUBLE dabs(const FCALC_DOUBLE x)
+{
+ return (x >= 0.0) ? x : -x;
+}
+
+MyMoneyFinancialCalculator::MyMoneyFinancialCalculator()
+{
+ setPrec();
+ setPF();
+ setCF();
+ setBep();
+ setDisc();
+
+ setNpp(0.0);
+ setIr(0.0);
+ setPv(0.0);
+ setPmt(0.0);
+ setFv(0.0);
+
+ // clear the mask
+ m_mask = 0;
+}
+
+MyMoneyFinancialCalculator::~MyMoneyFinancialCalculator()
+{
+}
+
+void MyMoneyFinancialCalculator::setPrec(const unsigned short prec)
+{
+ m_prec = prec;
+}
+
+void MyMoneyFinancialCalculator::setPF(const unsigned short PF)
+{
+ m_PF = PF;
+}
+
+void MyMoneyFinancialCalculator::setCF(const unsigned short CF)
+{
+ m_CF = CF;
+}
+
+void MyMoneyFinancialCalculator::setBep(const bool bep)
+{
+ m_bep = bep;
+}
+
+void MyMoneyFinancialCalculator::setDisc(const bool disc)
+{
+ m_disc = disc;
+}
+
+void MyMoneyFinancialCalculator::setIr(const FCALC_DOUBLE ir)
+{
+ m_ir = ir;
+ m_mask |= IR_SET;
+}
+
+void MyMoneyFinancialCalculator::setPv(const FCALC_DOUBLE pv)
+{
+ m_pv = pv;
+ m_mask |= PV_SET;
+}
+
+void MyMoneyFinancialCalculator::setPmt(const FCALC_DOUBLE pmt)
+{
+ m_pmt = pmt;
+ m_mask |= PMT_SET;
+}
+
+void MyMoneyFinancialCalculator::setNpp(const FCALC_DOUBLE npp)
+{
+ m_npp = npp;
+ m_mask |= NPP_SET;
+}
+
+void MyMoneyFinancialCalculator::setFv(const FCALC_DOUBLE fv)
+{
+ m_fv = fv;
+ m_mask |= FV_SET;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::numPayments(void)
+{
+ const unsigned short mask = PV_SET | IR_SET | PMT_SET | FV_SET;
+
+ if((m_mask & mask) != mask)
+ throw new MYMONEYEXCEPTION("Not all parameters set for calculation of numPayments");
+
+ FCALC_DOUBLE eint = eff_int();
+ FCALC_DOUBLE CC = _Cx(eint);
+
+ CC = (CC - m_fv) / (CC + m_pv);
+ m_npp = (CC > 0.0) ? logl (CC) / logl (eint +1.0) : 0.0;
+
+ m_mask |= NPP_SET;
+ return m_npp;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::payment(void)
+{
+ const unsigned short mask = PV_SET | IR_SET | NPP_SET | FV_SET;
+
+ if((m_mask & mask) != mask)
+ throw new MYMONEYEXCEPTION("Not all parameters set for calculation of payment");
+
+ FCALC_DOUBLE eint = eff_int();
+ FCALC_DOUBLE AA = _Ax(eint);
+ FCALC_DOUBLE BB = _Bx(eint);
+
+ m_pmt = -rnd((m_fv + m_pv * (AA + 1.0)) / (AA * BB));
+ //m_pmt = -floorl((m_fv + m_pv * (AA + 1.0)) / (AA * BB));
+
+ m_mask |= PMT_SET;
+ return m_pmt;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::presentValue(void)
+{
+ const unsigned short mask = PMT_SET | IR_SET | NPP_SET | FV_SET;
+
+ if((m_mask & mask) != mask)
+ throw new MYMONEYEXCEPTION("Not all parameters set for calculation of payment");
+
+ FCALC_DOUBLE eint = eff_int();
+ FCALC_DOUBLE AA = _Ax(eint);
+ FCALC_DOUBLE CC = _Cx(eint);
+
+ m_pv = rnd(-(m_fv + (AA * CC)) / (AA + 1.0));
+
+ m_mask |= PV_SET;
+ return m_pv;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::futureValue(void)
+{
+ const unsigned short mask = PMT_SET | IR_SET | NPP_SET | PV_SET;
+
+ if((m_mask & mask) != mask)
+ throw new MYMONEYEXCEPTION("Not all parameters set for calculation of payment");
+
+ FCALC_DOUBLE eint = eff_int();
+ FCALC_DOUBLE AA = _Ax(eint);
+ FCALC_DOUBLE CC = _Cx(eint);
+ m_fv = rnd(-(m_pv + AA * (m_pv + CC)));
+
+ m_mask |= FV_SET;
+ return m_fv;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::interestRate(void)
+{
+ FCALC_DOUBLE eint = 0.0;
+ FCALC_DOUBLE a = 0.0;
+ FCALC_DOUBLE dik = 0.0;
+
+ const FCALC_DOUBLE ratio = 1e4;
+ int ri;
+
+ if (m_pmt == 0.0) {
+ eint = powl ((dabs (m_fv) / dabs (m_pv)), (1.0 / m_npp)) - 1.0;
+ } else {
+ if ((m_pmt * m_fv) < 0.0) {
+ if(m_pv)
+ a = -1.0;
+ else
+ a = 1.0;
+ eint =
+ dabs ((m_fv + a * m_npp * m_pmt) /
+ (3.0 *
+ ((m_npp - 1.0) * (m_npp - 1.0) * m_pmt + m_pv -
+ m_fv)));
+ } else {
+ if ((m_pv * m_pmt) < 0.0) {
+ eint = dabs ((m_npp * m_pmt + m_pv + m_fv) / (m_npp * m_pv));
+ } else {
+ a = dabs (m_pmt / (dabs(m_pv) + dabs(m_fv)));
+ eint = a + 1.0 / (a * m_npp * m_npp * m_npp);
+ }
+ }
+ do {
+ try {
+ dik = _fi(eint) / _fip(eint);
+ eint -= dik;
+ } catch(MyMoneyException *e) {
+ delete e;
+ eint = 0;
+ }
+ (void) modfl(ratio * (dik / eint), &a);
+ ri = static_cast<unsigned> (a);
+ }
+ while (ri);
+ }
+ m_mask |= IR_SET;
+ m_ir = rnd(nom_int(eint) * 100.0);
+ return m_ir;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::_fi(const FCALC_DOUBLE eint) const
+{
+ return _Ax(eint) * (m_pv + _Cx(eint)) + m_pv + m_fv;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::_fip(const FCALC_DOUBLE eint) const
+{
+ double AA = _Ax(eint);
+ double CC = _Cx(eint);
+ double D = (AA + 1.0) / (eint + 1.0);
+
+ return m_npp *(m_pv + CC) * D - (AA * CC) / eint;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::_Ax(const FCALC_DOUBLE eint) const
+{
+ return powl ((eint + 1.0), m_npp) - 1.0;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::_Bx(const FCALC_DOUBLE eint) const
+{
+ if(eint == 0.0)
+ throw new MYMONEYEXCEPTION("Zero interest");
+
+ if(m_bep == false)
+ return static_cast<FCALC_DOUBLE>(1.0) / eint;
+
+ return (eint + 1.0) / eint;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::_Cx(const FCALC_DOUBLE eint) const
+{
+ return m_pmt * _Bx(eint);
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::eff_int(void) const
+{
+ FCALC_DOUBLE nint = m_ir / 100.0;
+ FCALC_DOUBLE eint;
+
+ if(m_disc) { // periodically compound?
+ if(m_CF == m_PF) { // same frequency?
+ eint = nint / static_cast<FCALC_DOUBLE>(m_CF);
+
+ } else {
+ eint = powl((static_cast<FCALC_DOUBLE>(1.0) + (nint / static_cast<FCALC_DOUBLE>(m_CF))),
+ (static_cast<FCALC_DOUBLE>(m_CF) / static_cast<FCALC_DOUBLE>(m_PF))) - 1.0;
+
+ }
+
+ } else {
+ eint = expl(nint / static_cast<FCALC_DOUBLE>(m_PF)) - 1.0;
+ }
+
+ return eint;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::nom_int(const FCALC_DOUBLE eint) const
+{
+ FCALC_DOUBLE nint;
+
+ if(m_disc) {
+ if(m_CF == m_PF) {
+ nint = m_CF * eint;
+
+ } else {
+ nint = m_CF * (powl ((eint + 1.0), (static_cast<FCALC_DOUBLE>(m_PF) / static_cast<FCALC_DOUBLE>(m_CF))) - 1.0);
+ }
+ } else
+ nint = logl (powl (eint + 1.0, m_PF));
+
+ return nint;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::interestDue(void) const
+{
+ FCALC_DOUBLE eint = eff_int();
+
+ return (m_pv + (m_bep ? m_pmt : 0.0)) * eint;
+}
+