diff --git a/components/fpspreadsheet/examples/other/financemath.pas b/components/fpspreadsheet/examples/other/financemath.pas
new file mode 100644
index 000000000..5dbe30121
--- /dev/null
+++ b/components/fpspreadsheet/examples/other/financemath.pas
@@ -0,0 +1,184 @@
+unit financemath;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils;
+
+{ Cash flow equation:
+
+ FV + PV * q^n + PMT (q^n - 1) / (q - 1) = 0 (1)
+
+ with
+
+ q = 1 + interest rate (RATE)
+ PV = present value of an investment
+ FV = future value of an investment
+ PMT = regular payment (per period)
+ n = NPER = number of payment periods
+
+ This is valid for payments occuring at the end of each period. If payments
+ occur at the start of each period the payments are multiplied by a factor q.
+ This case is indicated by means of the parameter PaymentTime below.
+
+ The interest rate is considered as "per period" - whatever that is.
+ If the period is 1 year then we use the "usual" interest rate.
+ If the period is 1 month then we use 1/12 of the yearly interest rate.
+
+ Sign rules:
+ - Money that I receive is to a positive number
+ - Money that I pay is to a negative number.
+
+ Example 1: Saving account
+ - A saving account has an initial balance of 1000 $ (PV).
+ I paid this money to the bank --> negative number
+ - I deposit 100$ regularly to this account (PMT): I pay this money --> negative number.
+ - At the end of the payments (NPER periods) I get the money back --> positive number.
+ This is the FV.
+
+ Example 2: Loan
+ - I borrow 1000$ from the bank: I get money --> positive PV
+ - I pay 100$ back to the bank in regular intervals --> negative PMT
+ - At the end, all debts are paid --> FV = 0.
+
+ The cash flow equation (1) contains 5 parameters (Rate, PV, FV, PMT, NPER).
+ The functions below solve this equation always for one of these parameters.
+
+ References:
+ - http://en.wikipedia.org/wiki/Time_value_of_money
+ - https://wiki.openoffice.org/wiki/Documentation/How_Tos/Calc:_Derivation_of_Financial_Formulas
+}
+
+type
+ TPaymentTime = (ptEndOfPeriod, ptStartOfPeriod);
+
+function FutureValue(ARate: Extended; NPeriods: Integer;
+ APayment, APresentValue: Extended; APaymentTime: TPaymentTime): Extended;
+
+function InterestRate(NPeriods: Integer; APayment, APresentValue, AFutureValue: Extended;
+ APaymentTime: TPaymentTime): Extended;
+
+function NumberOfPeriods(ARate, APayment, APresentValue, AFutureValue: Extended;
+ APaymentTime: TPaymentTime): Extended;
+
+function Payment(ARate: Extended; NPeriods: Integer;
+ APresentValue, AFutureValue: Extended; APaymentTime: TPaymentTime): Extended;
+
+function PresentValue(ARate: Extended; NPeriods: Integer;
+ APayment, AFutureValue: Extended; APaymentTime: TPaymentTime): Extended;
+
+
+implementation
+
+uses
+ math;
+
+function FutureValue(ARate: Extended; NPeriods: Integer;
+ APayment, APresentValue: Extended; APaymentTime: TPaymentTime): Extended;
+var
+ q, qn, factor: Extended;
+begin
+ if ARate = 0 then
+ Result := -APresentValue - APayment * NPeriods
+ else begin
+ q := 1.0 + ARate;
+ qn := power(q, NPeriods);
+ factor := (qn - 1) / (q - 1);
+ if APaymentTime = ptStartOfPeriod then
+ factor := factor * q;
+ Result := -(APresentValue * qn + APayment*factor);
+ end;
+end;
+
+function InterestRate(NPeriods: Integer; APayment, APresentValue, AFutureValue: Extended;
+ APaymentTime: TPaymentTime): Extended;
+{ The interest rate cannot be calculated analytically. We solve the equation
+ numerically by means of the Newton method:
+ - guess value for the interest reate
+ - calculate at which interest rate the tangent of the curve fv(rate)
+ (straight line!) has the requested future vale.
+ - use this rate for the next iteration. }
+const
+ DELTA = 0.001;
+ EPS = 1E-9; // required precision of interest rate (after typ. 6 iterations)
+ MAXIT = 20; // max iteration count to protect agains non-convergence
+var
+ r1, r2, dr: Extended;
+ fv1, fv2: Extended;
+ iteration: Integer;
+begin
+ iteration := 0;
+ r1 := 0.05; // inital guess
+ repeat
+ r2 := r1 + DELTA;
+ fv1 := FutureValue(r1, NPeriods, APayment, APresentValue, APaymentTime);
+ fv2 := FutureValue(r2, NPeriods, APayment, APresentValue, APaymentTime);
+ dr := (AFutureValue - fv1) / (fv2 - fv1) * delta; // tangent at fv(r)
+ r1 := r1 + dr; // next guess
+ inc(iteration);
+ until (abs(dr) < EPS) or (iteration >= MAXIT);
+ Result := r1;
+end;
+
+function NumberOfPeriods(ARate, APayment, APresentValue, AFutureValue: extended;
+ APaymentTime: TPaymentTime): extended;
+{ Solve the cash flow equation (1) for q^n and take the logarithm }
+var
+ q, x1, x2: Extended;
+begin
+ if ARate = 0 then
+ Result := -(APresentValue + AFutureValue) / APayment
+ else begin
+ q := 1.0 + ARate;
+ if APaymentTime = ptStartOfPeriod then
+ APayment := APayment * q;
+ x1 := APayment - AFutureValue * ARate;
+ x2 := APayment + APresentValue * ARate;
+ if (x2 = 0) // we have to divide by x2
+ or (sign(x1) * sign(x2) < 0) // the argument of the log is negative
+ then
+ Result := Infinity
+ else begin
+ Result := ln(x1/x2) / ln(q);
+ end;
+ end;
+end;
+
+function Payment(ARate: Extended; NPeriods: Integer;
+ APresentValue, AFutureValue: Extended; APaymentTime: TPaymentTime): Extended;
+var
+ q, qn, factor: Extended;
+begin
+ if ARate = 0 then
+ Result := -(AFutureValue + APresentValue) / NPeriods
+ else begin
+ q := 1.0 + ARate;
+ qn := power(q, NPeriods);
+ factor := (qn - 1) / (q - 1);
+ if APaymentTime = ptStartOfPeriod then
+ factor := factor * q;
+ Result := -(AFutureValue + APresentValue * qn) / factor;
+ end;
+end;
+
+function PresentValue(ARate: Extended; NPeriods: Integer;
+ APayment, AFutureValue: Extended; APaymentTime: TPaymentTime): Extended;
+var
+ q, qn, factor: Extended;
+begin
+ if ARate = 0.0 then
+ Result := -AFutureValue - APayment * NPeriods
+ else begin
+ q := 1.0 + ARate;
+ qn := power(q, NPeriods);
+ factor := (qn - 1) / (q - 1);
+ if APaymentTime = ptStartOfPeriod then
+ factor := factor * q;
+ Result := -(AFutureValue + APayment*factor) / qn;
+ end;
+end;
+
+end.
+
diff --git a/components/fpspreadsheet/examples/other/test_formula_func.lpi b/components/fpspreadsheet/examples/other/test_formula_func.lpi
index 7fe05078f..cf20902e9 100644
--- a/components/fpspreadsheet/examples/other/test_formula_func.lpi
+++ b/components/fpspreadsheet/examples/other/test_formula_func.lpi
@@ -60,12 +60,17 @@
-
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/examples/other/test_formula_func.lps b/components/fpspreadsheet/examples/other/test_formula_func.lps
index 39ac60b35..5b85ae9d9 100644
--- a/components/fpspreadsheet/examples/other/test_formula_func.lps
+++ b/components/fpspreadsheet/examples/other/test_formula_func.lps
@@ -4,204 +4,211 @@
-
+
-
-
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/components/fpspreadsheet/examples/other/test_formula_func.pas b/components/fpspreadsheet/examples/other/test_formula_func.pas
index 9412e09f9..ed10d0607 100644
--- a/components/fpspreadsheet/examples/other/test_formula_func.pas
+++ b/components/fpspreadsheet/examples/other/test_formula_func.pas
@@ -24,134 +24,29 @@ uses
{$ENDIF}{$ENDIF}
Classes, SysUtils, laz_fpspreadsheet
{ you can add units after this },
- math, fpspreadsheet, xlsbiff8, fpsfunc;
+ math, fpspreadsheet, xlsbiff8, fpsfunc, financemath;
{------------------------------------------------------------------------------}
-{ Basic implmentation of the four financial funtions }
-{------------------------------------------------------------------------------}
-
-const
- paymentAtEnd = 0;
- paymentAtBegin = 1;
-
-{ Calculates the future value (FV) of an investment based on an interest rate and
- a constant payment schedule:
- - "interest_rate" (r) is the interest rate for the investment (as decimal, not percent)
- - "number_periods" (n) is the number of payment periods, i.e. number of payments
- for the annuity.
- - "payment" (PMT) is the amount of the payment made each period
- - "pv" is the present value of the payments.
- - "payment_type" indicates when the payments are due (see paymentAtXXX constants)
-
- see: http://en.wikipedia.org/wiki/Time_value_of_money
- or https://wiki.openoffice.org/wiki/Documentation/How_Tos/Calc:_Derivation_of_Financial_Formulas#PV.2C_FV.2C_PMT.2C_NPER.2C_RATE
-
- As in Excel's implementation the cash flow is a signed number:
- - Positive cash flow means: "I get money"
- - Negative cash flow means: "I pay money"
-
- With these conventions, the contributions (FV, PV, Payments) add up to 0:
- FV + PV q^n + PMT (q^n - 1) / (q - 1) = 0 ( q = 1 + r )
-}
-function FV(interest_rate: Double; number_periods: Integer; payment, pv: Double;
- payment_type: integer): Double;
-var
- q, qn, factor: Double;
-begin
- q := 1.0 + interest_rate;
- qn := power(q, number_periods);
- factor := (qn - 1) / (q - 1);
- if payment_type = paymentAtBegin then
- factor := factor * q;
-
- Result := -(pv * qn + payment*factor);
-end;
-
-{ Calculates the number of periods for an investment based on an interest rate
- and a constant payment schedule.
- Solve above formula for qn and then take the log to get n.
- }
-function NPER(interest_rate, payment, pv, fv: Double;
- payment_type:Integer): double;
-var
- q, x1, x2, T: Double;
-begin
- if interest_rate = 0 then
- Result := (pv + fv) / payment
- else
- q := 1.0 + interest_rate;
- if payment_type = paymentAtBegin then
- payment := payment * q;
- x2 := pv * interest_rate + payment;
- if x2 = 0 then
- Result := Infinity
- else begin
- x1 := -fv * interest_rate + payment;
- Result := ln(x1/x2) / ln(q);
- end;
-end;
-
-{ Calculates the regular payments for a loan based on an interest rate and a
- constant payment schedule
- Arguments as shown for FV(), in addition:
- - "fv" is the future value of the payments.
- see: http://en.wikipedia.org/wiki/Time_value_of_money
- }
-function PMT(interest_rate: Double; number_periods: Integer; pv, fv: Double;
- payment_type: Integer): Double;
-var
- q, qn, factor: Double;
-begin
- q := 1.0 + interest_rate;
- qn := power(q, number_periods);
- factor := (qn - 1) / (q - 1);
- if payment_type = paymentAtBegin then
- factor := factor * q;
-
- Result := -(fv + pv * qn) / factor;
-end;
-
-{ Calculates the present value of an investment based on an interest rate and
- a constant payment schedule.
- Arguments as shown for FV(), in addition:
- - "fv" is the future value of the payments.
- see: http://en.wikipedia.org/wiki/Time_value_of_money
-}
-function PV(interest_rate: Double; number_periods: Integer; payment, fv: Double;
- payment_type: Integer): Double;
-var
- q, qn, factor: Double;
-begin
- q := 1.0 + interest_rate;
- qn := power(q, number_periods);
- factor := (qn - 1) / (q - 1);
- if payment_type = paymentAtBegin then
- factor := factor * q;
-
- Result := -(fv + payment*factor) / qn;
-end;
-
-
-{------------------------------------------------------------------------------}
-{ Adaption for usage by fpspreadsheet }
+{ Adaption of financial functions to usage by fpspreadsheet }
+{ The functions are implemented in the unit "financemath.pas". }
{------------------------------------------------------------------------------}
function fpsFV(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TsArgNumberArray;
begin
- // Pop the argument off the stack. This can be done by means of PopNumberValues
- // which brings the values back into the right order and reports an error
+ // Pop the argument from the stack. This can be done by means of PopNumberValues
+ // which brings the values back in the right order and reports an error
// in case of non-numerical values.
if Args.PopNumberValues(NumArgs, false, data, Result) then
- // Call our FV function with the NumberValues of the arguments.
- Result := CreateNumberArg(FV(
+ // Call the FutureValue function with the NumberValues of the arguments.
+ Result := CreateNumberArg(FutureValue(
data[0], // interest rate
round(data[1]), // number of payments
data[2], // payment
data[3], // present value
- round(data[4]) // payment type
+ TPaymentTime(round(data[4])) // payment type
));
end;
@@ -160,12 +55,12 @@ var
data: TsArgNumberArray;
begin
if Args.PopNumberValues(NumArgs, false, data, Result) then
- Result := CreateNumberArg(PMT(
+ Result := CreateNumberArg(Payment(
data[0], // interest rate
round(data[1]), // number of payments
data[2], // present value
data[3], // future value
- round(data[4]) // payment type
+ TPaymentTime(round(data[4])) // payment type
));
end;
@@ -174,12 +69,12 @@ var
data: TsArgNumberArray;
begin
if Args.PopNumberValues(NumArgs, false, data, Result) then
- Result := CreateNumberArg(PV(
+ Result := CreateNumberArg(PresentValue(
data[0], // interest rate
round(data[1]), // number of payments
data[2], // payment
data[3], // future value
- round(data[4]) // payment type
+ TPaymentTime(round(data[4])) // payment type
));
end;
@@ -188,12 +83,26 @@ var
data: TsArgNumberArray;
begin
if Args.PopNumberValues(NumArgs, false, data, Result) then
- Result := CreateNumberArg(NPER(
+ Result := CreateNumberArg(NumberOfPeriods(
data[0], // interest rate
data[1], // payment
data[2], // present value
data[3], // future value
- round(data[4]) // payment type
+ TPaymentTime(round(data[4])) // payment type
+ ));
+end;
+
+function fpsRATE(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TsArgNumberArray;
+begin
+ if Args.PopNumberValues(NumArgs, false, data, Result) then
+ Result := CreateNumberArg(InterestRate(
+ round(data[0]), // number of payment periods
+ data[1], // payment
+ data[2], // present value
+ data[3], // future value
+ TPaymentTime(round(data[4])) // payment type
));
end;
@@ -202,159 +111,192 @@ end;
{------------------------------------------------------------------------------}
procedure WriteFile(AFileName: String);
const
- INTEREST_RATE = 0.03;
- NUMBER_PAYMENTS = 10;
- PAYMENT = 1000;
- PRESENT_VALUE = 10000;
- PAYMENT_WHEN = paymentAtEnd;
+ INTEREST_RATE = 0.03; // interest rate per period
+ NUMBER_PAYMENTS = 10; // number of payment periods
+ REG_PAYMENT = 1000; // regular payment per period
+ PRESENT_VALUE = 10000; // present value of investment
+ PAYMENT_WHEN: TPaymentTime = ptEndOfPeriod; // when is the payment made
var
workbook: TsWorkbook;
worksheet: TsWorksheet;
- fval, pval, pmtval, nperval: Double;
+ fval, pval, pmtval, nperval, rateval: Double;
begin
- { We have to register our financial function in fpspreadsheet. Otherwise an
- error code would be displayed in the reading part of this demo in these
+ { We have to register our financial functions in fpspreadsheet. Otherwise an
+ error code would be displayed in the reading part of this demo for these
formula cells. }
RegisterFormulaFunc(fekFV, @fpsFV);
RegisterFormulaFunc(fekPMT, @fpsPMT);
RegisterFormulaFunc(fekPV, @fpsPV);
RegisterFormulaFunc(fekNPER, @fpsNPER);
+ RegisterFormulaFunc(fekRATE, @fpsRATE);
workbook := TsWorkbook.Create;
try
worksheet := workbook.AddWorksheet('Financial');
worksheet.Options := worksheet.Options + [soCalcBeforeSaving];
worksheet.WriteColWidth(0, 40);
+ worksheet.WriteColWidth(1, 15);
- worksheet.WriteUTF8Text(0, 0, 'Interest rate');
- worksheet.WriteNumber(0, 1, INTEREST_RATE, nfPercentage, 1); // B1
+ worksheet.WriteUTF8Text(0, 0, 'INPUT DATA');
+ worksheet.WriteFontStyle(0, 0, [fssBold]);
- worksheet.WriteUTF8Text(1, 0, 'Number of payments');
- worksheet.WriteNumber(1, 1, NUMBER_PAYMENTS); // B2
+ worksheet.WriteUTF8Text(1, 0, 'Interest rate');
+ worksheet.WriteNumber(1, 1, INTEREST_RATE, nfPercentage, 1); // B2
- worksheet.WriteUTF8Text(2, 0, 'Payment');
- worksheet.WriteCurrency(2, 1, PAYMENT, nfCurrency, 2, '$'); // B3
+ worksheet.WriteUTF8Text(2, 0, 'Number of payments');
+ worksheet.WriteNumber(2, 1, NUMBER_PAYMENTS); // B3
- worksheet.WriteUTF8Text(3, 0, 'Present value');
- worksheet.WriteCurrency(3, 1, PRESENT_VALUE, nfCurrency, 2, '$'); // B4
+ worksheet.WriteUTF8Text(3, 0, 'Payment');
+ worksheet.WriteCurrency(3, 1, REG_PAYMENT, nfCurrency, 2, '$'); // B4
- worksheet.WriteUTF8Text(4, 0, 'Payment at end (0) or at begin (1)');
- worksheet.WriteNumber(4, 1, PAYMENT_WHEN); // B5
+ worksheet.WriteUTF8Text(4, 0, 'Present value');
+ worksheet.WriteCurrency(4, 1, PRESENT_VALUE, nfCurrency, 2, '$'); // B5
+
+ worksheet.WriteUTF8Text(5, 0, 'Payment at end (0) or at begin (1)');
+ worksheet.WriteNumber(5, 1, ord(PAYMENT_WHEN)); // B6
// future value calculation
- fval := FV(INTEREST_RATE, NUMBER_PAYMENTS, PAYMENT, PRESENT_VALUE, PAYMENT_WHEN);
- worksheet.WriteUTF8Text(6, 0, 'Calculation of the future value');
- worksheet.WriteFontStyle(6, 0, [fssBold]);
- worksheet.WriteUTF8Text(7, 0, 'Our calculation');
- worksheet.WriteCurrency(7, 1, fval, nfCurrency, 2, '$');
+ fval := FutureValue(INTEREST_RATE, NUMBER_PAYMENTS, REG_PAYMENT, PRESENT_VALUE, PAYMENT_WHEN);
+ worksheet.WriteUTF8Text(7, 0, 'CALCULATION OF THE FUTURE VALUE');
+ worksheet.WriteFontStyle(7, 0, [fssBold]);
+ worksheet.WriteUTF8Text(8, 0, 'Direct calculation');
+ worksheet.WriteCurrency(8, 1, fval, nfCurrency, 2, '$');
- worksheet.WriteUTF8Text(8, 0, 'Excel''s calculation using constants');
- worksheet.WriteNumberFormat(8, 1, nfCurrency, 2, '$');
- worksheet.WriteRPNFormula(8, 1, CreateRPNFormula( // B9
+ worksheet.WriteUTF8Text(9, 0, 'Worksheet calculation using constants');
+ worksheet.WriteNumberFormat(9, 1, nfCurrency, 2, '$');
+ worksheet.WriteRPNFormula(9, 1, CreateRPNFormula(
RPNNumber(INTEREST_RATE,
RPNNumber(NUMBER_PAYMENTS,
- RPNNumber(PAYMENT,
+ RPNNumber(REG_PAYMENT,
RPNNumber(PRESENT_VALUE,
- RPNNumber(PAYMENT_WHEN,
+ RPNNumber(ord(PAYMENT_WHEN),
RPNFunc(fekFV, 5,
nil))))))));
- worksheet.WriteUTF8Text(9, 0, 'Excel''s calculation using cell values');
- worksheet.WriteNumberFormat(9, 1, nfCurrency, 2, '$');
- worksheet.WriteRPNFormula(9, 1, CreateRPNFormula( // B9
- RPNCellValue('B1', // interest rate
- RPNCellValue('B2', // number of periods
- RPNCellValue('B3', // payment
- RPNCellValue('B4', // present value
- RPNCellValue('B5', // payment at end or at start
+ worksheet.WriteUTF8Text(10, 0, 'Worksheet calculation using cell values');
+ worksheet.WriteNumberFormat(10, 1, nfCurrency, 2, '$');
+ worksheet.WriteRPNFormula(10, 1, CreateRPNFormula(
+ RPNCellValue('B2', // interest rate
+ RPNCellValue('B3', // number of periods
+ RPNCellValue('B4', // payment
+ RPNCellValue('B5', // present value
+ RPNCellValue('B6', // payment at end or at start
RPNFunc(fekFV, 5, // Call Excel's FV formula
nil))))))));
// present value calculation
- pval := PV(INTEREST_RATE, NUMBER_PAYMENTS, PAYMENT, fval, PAYMENT_WHEN);
- worksheet.WriteUTF8Text(11, 0, 'Calculation of the present value');
- worksheet.WriteFontStyle(11, 0, [fssBold]);
- worksheet.WriteUTF8Text(12, 0, 'Our calculation');
- worksheet.WriteCurrency(12, 1, pval, nfCurrency, 2, '$');
+ pval := PresentValue(INTEREST_RATE, NUMBER_PAYMENTS, REG_PAYMENT, fval, PAYMENT_WHEN);
+ worksheet.WriteUTF8Text(12, 0, 'CALCULATION OF THE PRESENT VALUE');
+ worksheet.WriteFontStyle(12, 0, [fssBold]);
+ worksheet.WriteUTF8Text(13, 0, 'Direct calculation');
+ worksheet.WriteCurrency(13, 1, pval, nfCurrency, 2, '$');
- worksheet.WriteUTF8Text(13, 0, 'Excel''s calculation using constants');
- worksheet.WriteNumberFormat(13, 1, nfCurrency, 2, '$');
- worksheet.WriteRPNFormula(13, 1, CreateRPNFormula(
- RPNNumber(INTEREST_RATE,
- RPNNumber(NUMBER_PAYMENTS,
- RPNNumber(PAYMENT,
- RPNNumber(fval,
- RPNNumber(PAYMENT_WHEN,
- RPNFunc(fekPV, 5,
- nil))))))));
- Worksheet.WriteUTF8Text(14, 0, 'Excel''s calculation using cell values');
+ worksheet.WriteUTF8Text(14, 0, 'Worksheet calculation using constants');
worksheet.WriteNumberFormat(14, 1, nfCurrency, 2, '$');
worksheet.WriteRPNFormula(14, 1, CreateRPNFormula(
- RPNCellValue('B1', // interest rate
- RPNCellValue('B2', // number of periods
- RPNCellValue('B3', // payment
- RPNCellValue('B10', // future value
- RPNCellValue('B5', // payment at end or at start
+ RPNNumber(INTEREST_RATE,
+ RPNNumber(NUMBER_PAYMENTS,
+ RPNNumber(REG_PAYMENT,
+ RPNNumber(fval,
+ RPNNumber(ord(PAYMENT_WHEN),
+ RPNFunc(fekPV, 5,
+ nil))))))));
+ Worksheet.WriteUTF8Text(15, 0, 'Worksheet calculation using cell values');
+ worksheet.WriteNumberFormat(15, 1, nfCurrency, 2, '$');
+ worksheet.WriteRPNFormula(15, 1, CreateRPNFormula(
+ RPNCellValue('B2', // interest rate
+ RPNCellValue('B3', // number of periods
+ RPNCellValue('B4', // payment
+ RPNCellValue('B11', // future value
+ RPNCellValue('B6', // payment at end or at start
RPNFunc(fekPV, 5, // Call Excel's PV formula
nil))))))));
// payments calculation
- pmtval := PMT(INTEREST_RATE, NUMBER_PAYMENTS, PRESENT_VALUE, fval, PAYMENT_WHEN);
- worksheet.WriteUTF8Text(16, 0, 'Calculation of the payment');
- worksheet.WriteFontStyle(16, 0, [fssBold]);
- worksheet.WriteUTF8Text(17, 0, 'Our calculation');
- worksheet.WriteCurrency(17, 1, pmtval, nfCurrency, 2, '$');
+ pmtval := Payment(INTEREST_RATE, NUMBER_PAYMENTS, PRESENT_VALUE, fval, PAYMENT_WHEN);
+ worksheet.WriteUTF8Text(17, 0, 'CALCULATION OF THE PAYMENT');
+ worksheet.WriteFontStyle(17, 0, [fssBold]);
+ worksheet.WriteUTF8Text(18, 0, 'Direct calculation');
+ worksheet.WriteCurrency(18, 1, pmtval, nfCurrency, 2, '$');
- worksheet.WriteUTF8Text(18, 0, 'Excel''s calculation using constants');
- worksheet.WriteNumberFormat(18, 1, nfCurrency, 2, '$');
- worksheet.WriteRPNFormula(18, 1, CreateRPNFormula(
+ worksheet.WriteUTF8Text(19, 0, 'Worksheet calculation using constants');
+ worksheet.WriteNumberFormat(19, 1, nfCurrency, 2, '$');
+ worksheet.WriteRPNFormula(19, 1, CreateRPNFormula(
RPNNumber(INTEREST_RATE,
RPNNumber(NUMBER_PAYMENTS,
RPNNumber(PRESENT_VALUE,
RPNNumber(fval,
- RPNNumber(PAYMENT_WHEN,
+ RPNNumber(ord(PAYMENT_WHEN),
RPNFunc(fekPMT, 5,
nil))))))));
- Worksheet.WriteUTF8Text(19, 0, 'Excel''s calculation using cell values');
- worksheet.WriteNumberFormat(19, 1, nfCurrency, 2, '$');
- worksheet.WriteRPNFormula(19, 1, CreateRPNFormula(
- RPNCellValue('B1', // interest rate
- RPNCellValue('B2', // number of periods
- RPNCellValue('B4', // present value
- RPNCellValue('B10', // future value
- RPNCellValue('B5', // payment at end or at start
+ Worksheet.WriteUTF8Text(20, 0, 'Worksheet calculation using cell values');
+ worksheet.WriteNumberFormat(20, 1, nfCurrency, 2, '$');
+ worksheet.WriteRPNFormula(20, 1, CreateRPNFormula(
+ RPNCellValue('B2', // interest rate
+ RPNCellValue('B3', // number of periods
+ RPNCellValue('B5', // present value
+ RPNCellValue('B11', // future value
+ RPNCellValue('B6', // payment at end or at start
RPNFunc(fekPMT, 5, // Call Excel's PMT formula
nil))))))));
// number of periods calculation
- nperval := NPER(INTEREST_RATE, PAYMENT, PRESENT_VALUE, fval, PAYMENT_WHEN);
- worksheet.WriteUTF8Text(21, 0, 'Calculation of the number of payment periods');
- worksheet.WriteFontStyle(21, 0, [fssBold]);
- worksheet.WriteUTF8Text(22, 0, 'Our calculation');
- worksheet.WriteNumber(22, 1, nperval, nfFixed, 2);
+ nperval := NumberOfPeriods(INTEREST_RATE, REG_PAYMENT, PRESENT_VALUE, fval, PAYMENT_WHEN);
+ worksheet.WriteUTF8Text(22, 0, 'CALCULATION OF THE NUMBER OF PAYMENT PERIODS');
+ worksheet.WriteFontStyle(22, 0, [fssBold]);
+ worksheet.WriteUTF8Text(23, 0, 'Direct calculation');
+ worksheet.WriteNumber(23, 1, nperval, nfFixed, 2);
- worksheet.WriteUTF8Text(23, 0, 'Excel''s calculation using constants');
- worksheet.WriteNumberFormat(23, 1, nfFixed, 2);
- worksheet.WriteRPNFormula(23, 1, CreateRPNFormula(
- RPNNumber(INTEREST_RATE,
- RPNNumber(PAYMENT,
- RPNNumber(PRESENT_VALUE,
- RPNNumber(fval,
- RPNNumber(PAYMENT_WHEN,
- RPNFunc(fekNPER, 5,
- nil))))))));
- Worksheet.WriteUTF8Text(24, 0, 'Excel''s calculation using cell values');
+ worksheet.WriteUTF8Text(24, 0, 'Worksheet calculation using constants');
worksheet.WriteNumberFormat(24, 1, nfFixed, 2);
worksheet.WriteRPNFormula(24, 1, CreateRPNFormula(
- RPNCellValue('B1', // interest rate
- RPNCellValue('B3', // payment
- RPNCellValue('B4', // present value
- RPNCellValue('B10', // future value
- RPNCellValue('B5', // payment at end or at start
+ RPNNumber(INTEREST_RATE,
+ RPNNumber(REG_PAYMENT,
+ RPNNumber(PRESENT_VALUE,
+ RPNNumber(fval,
+ RPNNumber(ord(PAYMENT_WHEN),
+ RPNFunc(fekNPER, 5,
+ nil))))))));
+ Worksheet.WriteUTF8Text(25, 0, 'Worksheet calculation using cell values');
+ worksheet.WriteNumberFormat(25, 1, nfFixed, 2);
+ worksheet.WriteRPNFormula(25, 1, CreateRPNFormula(
+ RPNCellValue('B2', // interest rate
+ RPNCellValue('B4', // payment
+ RPNCellValue('B5', // present value
+ RPNCellValue('B11', // future value
+ RPNCellValue('B6', // payment at end or at start
RPNFunc(fekNPER, 5, // Call Excel's PMT formula
nil))))))));
+ // interest rate calculation
+ rateval := InterestRate(NUMBER_PAYMENTS, REG_PAYMENT, PRESENT_VALUE, fval, PAYMENT_WHEN);
+ worksheet.WriteUTF8Text(27, 0, 'CALCULATION OF THE INTEREST RATE');
+ worksheet.WriteFontStyle(27, 0, [fssBold]);
+ worksheet.WriteUTF8Text(28, 0, 'Direct calculation');
+ worksheet.WriteNumber(28, 1, rateval, nfPercentage, 2);
+
+ worksheet.WriteUTF8Text(29, 0, 'Worksheet calculation using constants');
+ worksheet.WriteNumberFormat(29, 1, nfPercentage, 2);
+ worksheet.WriteRPNFormula(29, 1, CreateRPNFormula(
+ RPNNumber(NUMBER_PAYMENTS,
+ RPNNumber(REG_PAYMENT,
+ RPNNumber(PRESENT_VALUE,
+ RPNNumber(fval,
+ RPNNumber(ord(PAYMENT_WHEN),
+ RPNFunc(fekRATE, 5,
+ nil))))))));
+ Worksheet.WriteUTF8Text(30, 0, 'Worksheet calculation using cell values');
+ worksheet.WriteNumberFormat(30, 1, nfPercentage, 2);
+ worksheet.WriteRPNFormula(30, 1, CreateRPNFormula(
+ RPNCellValue('B3', // number of payments
+ RPNCellValue('B4', // payment
+ RPNCellValue('B5', // present value
+ RPNCellValue('B11', // future value
+ RPNCellValue('B6', // payment at end or at start
+ RPNFunc(fekRATE, 5, // Call Excel's PMT formula
+ nil))))))));
+
workbook.WriteToFile(AFileName, sfExcel8, true);
finally
@@ -389,6 +331,9 @@ begin
s2 := UTF8ToAnsi(worksheet.ReadAsUTF8Text(r, 1));
if s1 = '' then
WriteLn
+ else
+ if s2 = '' then
+ WriteLn(s1)
else
WriteLn(s1+': ':50, s2);
end;