![JAR search and dependency download from the Maven repository](/logo.png)
com.adobe.xfa.formcalc.BuiltinFinancial Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2007 Adobe Systems Incorporated All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual and
* technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or copyright
* law. Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained from
* Adobe Systems Incorporated.
*/
package com.adobe.xfa.formcalc;
/**
* This class defines static methods to implement
* the FormCalc financial calculations.
*
* F I N A N C I A L F U N C T I O N S
* apr, cterm, fv, ipmt, npv, pmt, ppmt, pv, rate, term.
*
* @author Mike P. Tardif
*
* @exclude from published api.
*/
final class BuiltinFinancial {
/*
* Disallow instances of this class.
*/
private BuiltinFinancial() {
}
/*
* Apr
* This function returns the annual percentage rate for a loan.
*/
static void Apr(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 3);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// promote the args to a doubles.
//
double nPrincipal = oParser.getNumeric(oArgSym[0]);
double nPayment = oParser.getNumeric(oArgSym[1]);
int nPeriods = (int) oParser.getNumeric(oArgSym[2]);
//
// range check the args.
//
if (nPrincipal <= 0. || nPayment <= 0. || nPeriods <= 0) {
throw new CalcException();
}
//
// compute the apr.
//
int maxIterations = 500;
final double eps = 0.005;
final double delta = 0.0000001;
double nInterest = 0.05;
double nPmtZero = nPrincipal / nPeriods;
double nPmtCur = LoanPmt(nPrincipal, nInterest, nPeriods);
int i = 1;
do {
if (Math.abs(nPmtCur - nPmtZero) < delta)
break;
nInterest *= (nPayment - nPmtZero) / (nPmtCur - nPmtZero);
nPmtCur = LoanPmt(nPrincipal, nInterest, nPeriods);
} while (! (++i > maxIterations || Math.abs(nPayment - nPmtCur) < eps));
double nRate = (Math.abs(nPmtCur - nPmtZero) < delta) ? 0. : 12 * nInterest;
oRetSym = new CalcSymbol(nRate);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Cterm
* This function returns the number of periods needed for an
* investment earning a fixed, but compounded interest rate to
* grow to a future value.
*/
static void Cterm(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
///
Builtins.minArgs(nArgs, 3);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// promote the args to a doubles.
//
double nInterest = oParser.getNumeric(oArgSym[0]);
double nFuture = oParser.getNumeric(oArgSym[1]);
double nPresent = oParser.getNumeric(oArgSym[2]);
//
// range check the args.
//
if (nInterest <= 0. || nFuture <= 0. || nPresent < 0.) {
throw new CalcException();
}
//
// compute the number of periods.
//
double nPeriods = Math.log(nFuture / nPresent)
/ Math.log(1 + nInterest);
oRetSym = new CalcSymbol(nPeriods);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Fv
* This function returns the future value of a series of equal payments
* at a fixed interest rate.
*/
static void Fv(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 3);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// promote the args to a doubles.
//
double nPayment = oParser.getNumeric(oArgSym[0]);
double nInterest = oParser.getNumeric(oArgSym[1]);
int nPeriods = (int) oParser.getNumeric(oArgSym[2]);
//
// range check the args.
//
if (nPeriods <= 0 || nPayment <= 0. || nInterest < 0.) {
throw new CalcException();
}
//
// compute the future value.
//
double nVal;
if (nInterest == 0.) {
nVal = nPayment * nPeriods;
}
//
// This is the formula which gives the old Filler 4.x answer (?)
// It assumes payment at the end of each period.
//
else {
nVal = nPayment * (1 + nInterest)
* (IntRate(nInterest, nPeriods - 1) - 1)
/ nInterest + nPayment;
}
//
// Apparently the correct MS Excel formula is (yeah, sure Bill):
// nPayment * (1 + nInterest)
// * (IntRate(nInterest, nPeriods) - 1) / nInterest;
//
oRetSym = new CalcSymbol(nVal);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Ipmt
* This function returns the amount of interest paid on a loan over a
* period of time.
*/
static void Ipmt(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 5);
Builtins.maxArgs(nArgs, 5);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// promote the args to a doubles.
//
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]);
//
// range check the args.
//
if (nPrincipal <= 0. || nInterest <= 0. || nPayment <= 0.)
throw new CalcException();
if (nStart < 1 || nMonths < 1)
throw new CalcException();
//
// compute the interest paid.
//
nInterest /= 12;
if (nPayment <= nPrincipal * nInterest) {
oRetSym = new CalcSymbol(0.);
}
else if (nMonths + nStart - 1
> LoanTerm(nPrincipal, nInterest, nPayment)) {
oRetSym = new CalcSymbol(0.);
}
else {
double nPrincipalRemaining = nPrincipal;
double nPrincipalPaidInPeriod = 0.;
double nInterestPaidInPeriod = 0.;
for (int i = 1; i < nStart; i++) {
nInterestPaidInPeriod = nPrincipalRemaining * nInterest;
nPrincipalPaidInPeriod = nPayment - nInterestPaidInPeriod;
nPrincipalRemaining -= nPrincipalPaidInPeriod;
if (nPrincipalRemaining <= 0.)
break;
}
double nInterestPaid = 0.;
for (int i = nStart; i < nStart + nMonths; i++) {
nInterestPaidInPeriod = nPrincipalRemaining * nInterest;
nPrincipalPaidInPeriod = nPayment - nInterestPaidInPeriod;
nPrincipalRemaining -= nPrincipalPaidInPeriod;
nInterestPaid += nInterestPaidInPeriod;
if (nPrincipalRemaining <= 0.)
break;
}
oRetSym = new CalcSymbol(nInterestPaid);
}
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Npv
* This function returns the net present value of an investment based
* on a future series of periodic cash flows and a discount rate.
*/
static void Npv(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 1);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// promote the arg to a double.
//
double nDiscountRate = oParser.getNumeric(oArgSym[0]);
//
// range check the args.
//
if (nDiscountRate <= 0.) {
throw new CalcException();
}
//
// compute the net present value.
//
double nVal = 0.;
double nDenom = 1.;
for (int i = 1; i < nArgs; i++) {
nDenom *= (1 + nDiscountRate);
nVal += oParser.getNumeric(oArgSym[i]) / nDenom;
}
oRetSym = new CalcSymbol(nVal);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Pmt
* This function returns the loan payment for a given principal,
* interest, and term.
*/
static void Pmt(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 3);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// promote the args to doubles.
//
double nPrincipal = oParser.getNumeric(oArgSym[0]);
double nInterest = oParser.getNumeric(oArgSym[1]);
int nPeriods = (int) oParser.getNumeric(oArgSym[2]);
//
// range check the args.
//
if (nPrincipal <= 0. || nInterest <= 0. || nPeriods <= 0) {
throw new CalcException();
}
//
// compute the payment.
//
double nPayment = LoanPmt(nPrincipal, nInterest, nPeriods);
oRetSym = new CalcSymbol(nPayment);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Ppmt
* This function returns the amount of principal paid on a loan
* over a period of time.
*/
static void Ppmt(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 5);
Builtins.maxArgs(nArgs, 5);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// promote the args to a doubles.
//
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]);
//
// range check the args.
//
if (nPrincipal <= 0. || nInterest <= 0. || nPayment <= 0.)
throw new CalcException();
if (nStart < 1 || nMonths < 1)
throw new CalcException();
//
// compute the principle paid.
//
nInterest /= 12;
if (nPayment <= nPrincipal * nInterest) {
oRetSym = new CalcSymbol(0.);
}
else if (nMonths + nStart - 1
> LoanTerm(nPrincipal, nInterest, nPayment)) {
oRetSym = new CalcSymbol(0.);
}
else {
double nPrincipalRemaining = nPrincipal;
double nPrincipalPaidInPeriod = 0.;
double nInterestPaidInPeriod = 0.;
for (int i = 1; i < nStart; i++) {
nInterestPaidInPeriod = nPrincipalRemaining * nInterest;
nPrincipalPaidInPeriod = nPayment - nInterestPaidInPeriod;
nPrincipalRemaining -= nPrincipalPaidInPeriod;
if (nPrincipalRemaining <= 0.)
break;
}
double nPrinciplePaid = 0.;
for (int i = nStart; i < nStart + nMonths; i++) {
nInterestPaidInPeriod = nPrincipalRemaining * nInterest;
nPrincipalPaidInPeriod = nPayment - nInterestPaidInPeriod;
nPrincipalRemaining -= nPrincipalPaidInPeriod;
nPrinciplePaid += nPrincipalPaidInPeriod;
if (nPrincipalRemaining <= 0.)
break;
}
oRetSym = new CalcSymbol(nPrinciplePaid);
}
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Pv
* This function returns the present value of an investment
* given an equal payment per period, a specific interest rate,
* and a number of periods.
*/
static void Pv(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 3);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// promote the arg to a double.
//
double nPayment = oParser.getNumeric(oArgSym[0]);
double nInterest = oParser.getNumeric(oArgSym[1]);
int nPeriods = (int) oParser.getNumeric(oArgSym[2]);
//
// range check the args.
//
if (nPeriods <= 0 || nPayment <= 0.) {
throw new CalcException();
}
//
// compute the present value.
//
double nVal;
if (nInterest == 0.) {
nVal = nPayment * nPeriods;
}
else {
nVal = nPayment * (1 - 1 / IntRate(nInterest, nPeriods))
/ nInterest;
}
oRetSym = new CalcSymbol(nVal);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Rate
* This function returns the compound interest rate per period
* required for an investment to grow from present to future value
* in a specified period.
*/
static void Rate(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 3);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// promote the args to a doubles.
//
double nFuture = oParser.getNumeric(oArgSym[0]);
double nPresent = oParser.getNumeric(oArgSym[1]);
double nPeriods = (int) oParser.getNumeric(oArgSym[2]);
//
// range check the args.
//
if (nFuture <= 0. || nPresent <= 0. || nPeriods <= 0) {
throw new CalcException();
}
//
// compute the rate.
//
double nRate
= Math.exp(Math.log(nFuture / nPresent) / nPeriods) - 1;
oRetSym = new CalcSymbol(nRate);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Term
* This function returns the number of periods needed for an
* investment earning a fixed, but compounded interest rate
* to grow to a future value.
*/
static void Term(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 3);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// promote the args to a doubles.
//
double nPayment = oParser.getNumeric(oArgSym[0]);
double nInterest = oParser.getNumeric(oArgSym[1]);
double nFuture = oParser.getNumeric(oArgSym[2]);
//
// range check the args.
//
if (nPayment <= 0. || nInterest <= 0. || nFuture <= 0.) {
throw new CalcException();
}
//
// compute the number of periods.
//
double nPeriods;
if (nFuture <= nPayment) {
nPeriods = 1;
}
else {
//
// Modified formula: assumes payment at the end of each period
//
nPeriods = Math.log((nFuture - nPayment) / nPayment * nInterest
+ (1 + nInterest)) / Math.log(1 + nInterest);
}
oRetSym = new CalcSymbol(nPeriods);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Returns the compound interest rate from the formula: (1 + i) ** p
*/
private static double IntRate(double nInterest, int nPeriods) {
double nRate = 1.;
for (int i = 0; i < nPeriods; i++)
nRate *= 1. + nInterest;
return nRate;
}
/*
* Returns the term of the loan.
*/
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;
}
/*
* Returns the loan payment for a given principal, interest, and term.
*/
private static double LoanPmt(double nPrincipal,
double nInterest, int nPeriods) {
return (nPrincipal / ((1 - 1 / IntRate(nInterest, nPeriods))
/ nInterest));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy