BuiltinFinancial.java 15.7 KB
/*
 * Decompiled with CFR 0_118.
 */
package com.adobe.xfa.formcalc;

import com.adobe.xfa.formcalc.Builtins;
import com.adobe.xfa.formcalc.CalcException;
import com.adobe.xfa.formcalc.CalcParser;
import com.adobe.xfa.formcalc.CalcSymbol;
import com.adobe.xfa.formcalc.Stack;

final class BuiltinFinancial {
    private BuiltinFinancial() {
    }

    static void Apr(CalcParser oParser, CalcSymbol[] oArgSym) {
        CalcSymbol oRetSym;
        block4 : {
            int nArgs = oArgSym.length;
            oRetSym = null;
            try {
                Builtins.minArgs(nArgs, 3);
                Builtins.maxArgs(nArgs, 3);
                Builtins.limitExceptionArgs(oArgSym);
                Builtins.limitNullArgs(oParser, nArgs, oArgSym);
                double nPrincipal = oParser.getNumeric(oArgSym[0]);
                double nPayment = oParser.getNumeric(oArgSym[1]);
                int nPeriods = (int)oParser.getNumeric(oArgSym[2]);
                if (nPrincipal <= 0.0 || nPayment <= 0.0 || nPeriods <= 0) {
                    throw new CalcException();
                }
                int maxIterations = 500;
                double eps = 0.005;
                double delta = 1.0E-7;
                double nInterest = 0.05;
                double nPmtZero = nPrincipal / (double)nPeriods;
                double nPmtCur = BuiltinFinancial.LoanPmt(nPrincipal, nInterest, nPeriods);
                int i = 1;
                while (Math.abs(nPmtCur - nPmtZero) >= 1.0E-7) {
                    nPmtCur = BuiltinFinancial.LoanPmt(nPrincipal, nInterest *= (nPayment - nPmtZero) / (nPmtCur - nPmtZero), nPeriods);
                    if (++i <= maxIterations && Math.abs(nPayment - nPmtCur) >= 0.005) continue;
                }
                double nRate = Math.abs(nPmtCur - nPmtZero) < 1.0E-7 ? 0.0 : 12.0 * nInterest;
                oRetSym = new CalcSymbol(nRate);
            }
            catch (CalcException e) {
                oRetSym = e.getSymbol();
                if (oRetSym.getType() == 1) break block4;
                oParser.mbInThrow = true;
            }
        }
        oParser.mStack.push(oRetSym);
    }

    static void Cterm(CalcParser oParser, CalcSymbol[] oArgSym) {
        CalcSymbol oRetSym;
        block3 : {
            int nArgs = oArgSym.length;
            oRetSym = null;
            try {
                Builtins.minArgs(nArgs, 3);
                Builtins.maxArgs(nArgs, 3);
                Builtins.limitExceptionArgs(oArgSym);
                Builtins.limitNullArgs(oParser, nArgs, oArgSym);
                double nInterest = oParser.getNumeric(oArgSym[0]);
                double nFuture = oParser.getNumeric(oArgSym[1]);
                double nPresent = oParser.getNumeric(oArgSym[2]);
                if (nInterest <= 0.0 || nFuture <= 0.0 || nPresent < 0.0) {
                    throw new CalcException();
                }
                double nPeriods = Math.log(nFuture / nPresent) / Math.log(1.0 + nInterest);
                oRetSym = new CalcSymbol(nPeriods);
            }
            catch (CalcException e) {
                oRetSym = e.getSymbol();
                if (oRetSym.getType() == 1) break block3;
                oParser.mbInThrow = true;
            }
        }
        oParser.mStack.push(oRetSym);
    }

    static void Fv(CalcParser oParser, CalcSymbol[] oArgSym) {
        CalcSymbol oRetSym;
        block3 : {
            int nArgs = oArgSym.length;
            oRetSym = null;
            try {
                Builtins.minArgs(nArgs, 3);
                Builtins.maxArgs(nArgs, 3);
                Builtins.limitExceptionArgs(oArgSym);
                Builtins.limitNullArgs(oParser, nArgs, oArgSym);
                double nPayment = oParser.getNumeric(oArgSym[0]);
                double nInterest = oParser.getNumeric(oArgSym[1]);
                int nPeriods = (int)oParser.getNumeric(oArgSym[2]);
                if (nPeriods <= 0 || nPayment <= 0.0 || nInterest < 0.0) {
                    throw new CalcException();
                }
                double nVal = nInterest == 0.0 ? nPayment * (double)nPeriods : nPayment * (1.0 + nInterest) * (BuiltinFinancial.IntRate(nInterest, nPeriods - 1) - 1.0) / nInterest + nPayment;
                oRetSym = new CalcSymbol(nVal);
            }
            catch (CalcException e) {
                oRetSym = e.getSymbol();
                if (oRetSym.getType() == 1) break block3;
                oParser.mbInThrow = true;
            }
        }
        oParser.mStack.push(oRetSym);
    }

    static void Ipmt(CalcParser oParser, CalcSymbol[] oArgSym) {
        CalcSymbol oRetSym;
        block10 : {
            int nArgs = oArgSym.length;
            oRetSym = null;
            try {
                Builtins.minArgs(nArgs, 5);
                Builtins.maxArgs(nArgs, 5);
                Builtins.limitExceptionArgs(oArgSym);
                Builtins.limitNullArgs(oParser, nArgs, oArgSym);
                double nPrincipal = oParser.getNumeric(oArgSym[0]);
                double nInterest = oParser.getNumeric(oArgSym[1]);
                double nPayment = oParser.getNumeric(oArgSym[2]);
                int nStart = (int)oParser.getNumeric(oArgSym[3]);
                int nMonths = (int)oParser.getNumeric(oArgSym[4]);
                if (nPrincipal <= 0.0 || nInterest <= 0.0 || nPayment <= 0.0) {
                    throw new CalcException();
                }
                if (nStart < 1 || nMonths < 1) {
                    throw new CalcException();
                }
                if (nPayment <= nPrincipal * (nInterest /= 12.0)) {
                    oRetSym = new CalcSymbol(0.0);
                } else if (nMonths + nStart - 1 > BuiltinFinancial.LoanTerm(nPrincipal, nInterest, nPayment)) {
                    oRetSym = new CalcSymbol(0.0);
                } else {
                    double nPrincipalRemaining = nPrincipal;
                    double nPrincipalPaidInPeriod = 0.0;
                    double nInterestPaidInPeriod = 0.0;
                    for (int i = 1; i < nStart && (nPrincipalRemaining -= (nPrincipalPaidInPeriod = nPayment - (nInterestPaidInPeriod = nPrincipalRemaining * nInterest))) > 0.0; ++i) {
                    }
                    double nInterestPaid = 0.0;
                    for (int i2 = nStart; i2 < nStart + nMonths; ++i2) {
                        nInterestPaidInPeriod = nPrincipalRemaining * nInterest;
                        nPrincipalPaidInPeriod = nPayment - nInterestPaidInPeriod;
                        nInterestPaid += nInterestPaidInPeriod;
                        if ((nPrincipalRemaining -= nPrincipalPaidInPeriod) <= 0.0) break;
                    }
                    oRetSym = new CalcSymbol(nInterestPaid);
                }
            }
            catch (CalcException e) {
                oRetSym = e.getSymbol();
                if (oRetSym.getType() == 1) break block10;
                oParser.mbInThrow = true;
            }
        }
        oParser.mStack.push(oRetSym);
    }

    static void Npv(CalcParser oParser, CalcSymbol[] oArgSym) {
        CalcSymbol oRetSym;
        block4 : {
            int nArgs = oArgSym.length;
            oRetSym = null;
            try {
                Builtins.minArgs(nArgs, 1);
                Builtins.limitExceptionArgs(oArgSym);
                Builtins.limitNullArgs(oParser, nArgs, oArgSym);
                double nDiscountRate = oParser.getNumeric(oArgSym[0]);
                if (nDiscountRate <= 0.0) {
                    throw new CalcException();
                }
                double nVal = 0.0;
                double nDenom = 1.0;
                for (int i = 1; i < nArgs; ++i) {
                    nVal += oParser.getNumeric(oArgSym[i]) / (nDenom *= 1.0 + nDiscountRate);
                }
                oRetSym = new CalcSymbol(nVal);
            }
            catch (CalcException e) {
                oRetSym = e.getSymbol();
                if (oRetSym.getType() == 1) break block4;
                oParser.mbInThrow = true;
            }
        }
        oParser.mStack.push(oRetSym);
    }

    static void Pmt(CalcParser oParser, CalcSymbol[] oArgSym) {
        CalcSymbol oRetSym;
        block3 : {
            int nArgs = oArgSym.length;
            oRetSym = null;
            try {
                Builtins.minArgs(nArgs, 3);
                Builtins.maxArgs(nArgs, 3);
                Builtins.limitExceptionArgs(oArgSym);
                Builtins.limitNullArgs(oParser, nArgs, oArgSym);
                double nPrincipal = oParser.getNumeric(oArgSym[0]);
                double nInterest = oParser.getNumeric(oArgSym[1]);
                int nPeriods = (int)oParser.getNumeric(oArgSym[2]);
                if (nPrincipal <= 0.0 || nInterest <= 0.0 || nPeriods <= 0) {
                    throw new CalcException();
                }
                double nPayment = BuiltinFinancial.LoanPmt(nPrincipal, nInterest, nPeriods);
                oRetSym = new CalcSymbol(nPayment);
            }
            catch (CalcException e) {
                oRetSym = e.getSymbol();
                if (oRetSym.getType() == 1) break block3;
                oParser.mbInThrow = true;
            }
        }
        oParser.mStack.push(oRetSym);
    }

    static void Ppmt(CalcParser oParser, CalcSymbol[] oArgSym) {
        CalcSymbol oRetSym;
        block10 : {
            int nArgs = oArgSym.length;
            oRetSym = null;
            try {
                Builtins.minArgs(nArgs, 5);
                Builtins.maxArgs(nArgs, 5);
                Builtins.limitExceptionArgs(oArgSym);
                Builtins.limitNullArgs(oParser, nArgs, oArgSym);
                double nPrincipal = oParser.getNumeric(oArgSym[0]);
                double nInterest = oParser.getNumeric(oArgSym[1]);
                double nPayment = oParser.getNumeric(oArgSym[2]);
                int nStart = (int)oParser.getNumeric(oArgSym[3]);
                int nMonths = (int)oParser.getNumeric(oArgSym[4]);
                if (nPrincipal <= 0.0 || nInterest <= 0.0 || nPayment <= 0.0) {
                    throw new CalcException();
                }
                if (nStart < 1 || nMonths < 1) {
                    throw new CalcException();
                }
                if (nPayment <= nPrincipal * (nInterest /= 12.0)) {
                    oRetSym = new CalcSymbol(0.0);
                } else if (nMonths + nStart - 1 > BuiltinFinancial.LoanTerm(nPrincipal, nInterest, nPayment)) {
                    oRetSym = new CalcSymbol(0.0);
                } else {
                    double nPrincipalRemaining = nPrincipal;
                    double nPrincipalPaidInPeriod = 0.0;
                    double nInterestPaidInPeriod = 0.0;
                    for (int i = 1; i < nStart && (nPrincipalRemaining -= (nPrincipalPaidInPeriod = nPayment - (nInterestPaidInPeriod = nPrincipalRemaining * nInterest))) > 0.0; ++i) {
                    }
                    double nPrinciplePaid = 0.0;
                    for (int i2 = nStart; i2 < nStart + nMonths; ++i2) {
                        nInterestPaidInPeriod = nPrincipalRemaining * nInterest;
                        nPrincipalPaidInPeriod = nPayment - nInterestPaidInPeriod;
                        nPrinciplePaid += nPrincipalPaidInPeriod;
                        if ((nPrincipalRemaining -= nPrincipalPaidInPeriod) <= 0.0) break;
                    }
                    oRetSym = new CalcSymbol(nPrinciplePaid);
                }
            }
            catch (CalcException e) {
                oRetSym = e.getSymbol();
                if (oRetSym.getType() == 1) break block10;
                oParser.mbInThrow = true;
            }
        }
        oParser.mStack.push(oRetSym);
    }

    static void Pv(CalcParser oParser, CalcSymbol[] oArgSym) {
        CalcSymbol oRetSym;
        block3 : {
            int nArgs = oArgSym.length;
            oRetSym = null;
            try {
                Builtins.minArgs(nArgs, 3);
                Builtins.maxArgs(nArgs, 3);
                Builtins.limitExceptionArgs(oArgSym);
                Builtins.limitNullArgs(oParser, nArgs, oArgSym);
                double nPayment = oParser.getNumeric(oArgSym[0]);
                double nInterest = oParser.getNumeric(oArgSym[1]);
                int nPeriods = (int)oParser.getNumeric(oArgSym[2]);
                if (nPeriods <= 0 || nPayment <= 0.0) {
                    throw new CalcException();
                }
                double nVal = nInterest == 0.0 ? nPayment * (double)nPeriods : nPayment * (1.0 - 1.0 / BuiltinFinancial.IntRate(nInterest, nPeriods)) / nInterest;
                oRetSym = new CalcSymbol(nVal);
            }
            catch (CalcException e) {
                oRetSym = e.getSymbol();
                if (oRetSym.getType() == 1) break block3;
                oParser.mbInThrow = true;
            }
        }
        oParser.mStack.push(oRetSym);
    }

    static void Rate(CalcParser oParser, CalcSymbol[] oArgSym) {
        CalcSymbol oRetSym;
        block3 : {
            int nArgs = oArgSym.length;
            oRetSym = null;
            try {
                Builtins.minArgs(nArgs, 3);
                Builtins.maxArgs(nArgs, 3);
                Builtins.limitExceptionArgs(oArgSym);
                Builtins.limitNullArgs(oParser, nArgs, oArgSym);
                double nFuture = oParser.getNumeric(oArgSym[0]);
                double nPresent = oParser.getNumeric(oArgSym[1]);
                double nPeriods = (int)oParser.getNumeric(oArgSym[2]);
                if (nFuture <= 0.0 || nPresent <= 0.0 || nPeriods <= 0.0) {
                    throw new CalcException();
                }
                double nRate = Math.exp(Math.log(nFuture / nPresent) / nPeriods) - 1.0;
                oRetSym = new CalcSymbol(nRate);
            }
            catch (CalcException e) {
                oRetSym = e.getSymbol();
                if (oRetSym.getType() == 1) break block3;
                oParser.mbInThrow = true;
            }
        }
        oParser.mStack.push(oRetSym);
    }

    static void Term(CalcParser oParser, CalcSymbol[] oArgSym) {
        CalcSymbol oRetSym;
        block3 : {
            int nArgs = oArgSym.length;
            oRetSym = null;
            try {
                Builtins.minArgs(nArgs, 3);
                Builtins.maxArgs(nArgs, 3);
                Builtins.limitExceptionArgs(oArgSym);
                Builtins.limitNullArgs(oParser, nArgs, oArgSym);
                double nPayment = oParser.getNumeric(oArgSym[0]);
                double nInterest = oParser.getNumeric(oArgSym[1]);
                double nFuture = oParser.getNumeric(oArgSym[2]);
                if (nPayment <= 0.0 || nInterest <= 0.0 || nFuture <= 0.0) {
                    throw new CalcException();
                }
                double nPeriods = nFuture <= nPayment ? 1.0 : Math.log((nFuture - nPayment) / nPayment * nInterest + (1.0 + nInterest)) / Math.log(1.0 + nInterest);
                oRetSym = new CalcSymbol(nPeriods);
            }
            catch (CalcException e) {
                oRetSym = e.getSymbol();
                if (oRetSym.getType() == 1) break block3;
                oParser.mbInThrow = true;
            }
        }
        oParser.mStack.push(oRetSym);
    }

    private static double IntRate(double nInterest, int nPeriods) {
        double nRate = 1.0;
        for (int i = 0; i < nPeriods; ++i) {
            nRate *= 1.0 + nInterest;
        }
        return nRate;
    }

    private static int LoanTerm(double nPrincipal, double nInterest, double nPayment) {
        double nRemaining = nPrincipal;
        int nMonths = 0;
        while (nRemaining > 0.0) {
            nRemaining = nRemaining - nPayment + nRemaining * nInterest;
            ++nMonths;
        }
        return nMonths;
    }

    private static double LoanPmt(double nPrincipal, double nInterest, int nPeriods) {
        return nPrincipal / ((1.0 - 1.0 / BuiltinFinancial.IntRate(nInterest, nPeriods)) / nInterest);
    }
}