5 // Chris J Breisch (cjbreisch@altavista.net)
7 // (C) 2002 Chris J Breisch
11 using System.ComponentModel;
\r
12 using System.Runtime.InteropServices;
13 using Microsoft.VisualBasic.CompilerServices;
15 namespace Microsoft.VisualBasic
\r
18 sealed public class Financial {
21 private Financial() {} // prevent public default constructor
24 public static double DDB (double Cost, double Salvage, double Life, double Period,
25 [Optional, DefaultValue (2)] double Factor)
27 // LAMESPEC: MSDN says Life and Factor only throws exception if < 0, but Implementation throws exception if <= 0
34 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "Factor"));
36 return (((Cost - Salvage) * Factor) / Life) * Period;
39 public static double FV (double Rate, double NPer, double Pmt,
40 [Optional, DefaultValue (0)] double PV,
41 [Optional, DefaultValue (0)] DueDate Due)
45 double currentRate = Math.Pow (Rate + 1, NPer);
49 sum = Pmt * ((currentRate - 1) / Rate);
53 if (Due == DueDate.BegOfPeriod)
56 return PV * currentRate + sum;
59 public static double IPmt (double Rate, double Per, double NPer, double PV,
60 [Optional, DefaultValue (0)] double FV,
61 [Optional, DefaultValue (0)] DueDate Due)
63 double totalFutureVal;
64 double totalPaymentValue;
65 double numberOfPeriods;
67 if ((Per <= 0) || (Per >= (NPer + 1)))
68 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "Per"));
69 if ((Due == DueDate.BegOfPeriod) && (Per == 1))
72 totalPaymentValue = Pmt (Rate, NPer, PV, FV, Due);
73 if (Due == DueDate.BegOfPeriod)
74 PV = (PV + totalPaymentValue);
76 numberOfPeriods = Per - ((int)Due) - 1;
78 Financial.FV (Rate, numberOfPeriods, totalPaymentValue, PV, DueDate.EndOfPeriod);
80 return (totalFutureVal * Rate);
83 public static double IRR (ref double[] ValueArray, [Optional, DefaultValue (0.1)] double Guess)
85 double origPV, updatedPV, updateGuess, tmp;
86 double rateDiff = 0.0;
90 // MS.NET 2.0 docs say that Guess may not be <= -1
92 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "Guess"));
94 length = ValueArray.GetLength(0);
97 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "ValueArray"));
100 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "ValueArray"));
102 origPV = NPV (Guess, ref ValueArray);
103 updateGuess = (origPV > 0) ? Guess + 0.00001 : Guess - 0.00001;
105 if (updateGuess < -1)
106 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "Rate"));
108 rateDiff = updateGuess - Guess;
109 updatedPV = NPV (updateGuess, ref ValueArray);
110 pvDiff = updatedPV - origPV;
111 for (int i = 0; i < 20; i++) {
112 Guess = (updateGuess > Guess) ? (Guess - 0.00001) : (Guess + 0.00001);
113 origPV = NPV (Guess, ref ValueArray);
114 rateDiff = updateGuess - Guess;
115 pvDiff = updatedPV - origPV;
117 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue"));
118 Guess = updateGuess - (rateDiff * updatedPV / pvDiff);
121 origPV = NPV (Guess, ref ValueArray);
122 if ((Math.Abs (origPV) < 0.0000001) && (Math.Abs (rateDiff) < 0.00001))
132 double origPVAbs = Math.Abs (origPV);
133 double updatedPVAbs = Math.Abs (updatedPV);
134 if ((origPVAbs < 0.0000001) && (updatedPVAbs < 0.0000001))
135 return (origPVAbs < updatedPVAbs) ? Guess : updateGuess;
136 else if (origPVAbs < 0.0000001)
138 else if (updatedPVAbs < 0.0000001)
141 throw new ArgumentException(Utils.GetResourceString ("Argument_InvalidValue"));
144 public static double MIRR (ref double[] ValueArray, double FinanceRate, double ReinvestRate)
146 double [] array = ValueArray;
148 double assetsVal = 0;
149 double currentLoanRate = 1;
150 double currentAssetsRate = 1;
151 double totalInterestRate = 0;
154 throw new ArgumentException (Utils.GetResourceString ("Argument_RankEQOne1", "ValueArray"));
155 else if (FinanceRate == -1)
156 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "FinanceRate"));
157 else if (ReinvestRate == -1)
158 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "ReinvestRate"));
160 arrayLength = array.Length;
162 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "ValueArray"));
164 for (int i = 0; i < arrayLength; i++) {
165 currentLoanRate *= (1 + FinanceRate);
166 currentAssetsRate *= (1 + ReinvestRate);
168 loansVal += (array [i] / currentLoanRate);
169 else if (array [i] > 0)
170 assetsVal += (array [i] / currentAssetsRate);
174 throw new DivideByZeroException (Utils.GetResourceString ("Financial_CalcDivByZero"));
177 ((-assetsVal * Math.Pow (ReinvestRate + 1, arrayLength))
178 / (loansVal * (FinanceRate + 1)));
179 if (totalInterestRate < 0)
180 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue"));
182 return (Math.Pow (totalInterestRate, 1 / (double) (arrayLength - 1))) - 1;
185 public static double NPer (double Rate, double Pmt, double PV,
186 [Optional, DefaultValue (0)] double FV,
187 [Optional, DefaultValue (0)] DueDate Due)
189 double totalIncomeFromFlow, sumOfPvAndPayment, currentValueOfPvAndPayment;
190 if (Rate == 0 && Pmt == 0)
191 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "Pmt"));
193 return (- (PV + FV) / Pmt);
194 // MainSoft had Rate < -1, but MS.NET 2.0 Doc says Rate should not be <= -1
196 throw new ArgumentException(Utils.GetResourceString ("Argument_InvalidValue1", "Rate"));
197 totalIncomeFromFlow = (Pmt / Rate);
198 if (Due == DueDate.BegOfPeriod)
199 totalIncomeFromFlow *= (1 + Rate);
201 sumOfPvAndPayment = (-FV + totalIncomeFromFlow);
202 currentValueOfPvAndPayment = (PV + totalIncomeFromFlow);
203 if ((sumOfPvAndPayment < 0) && (currentValueOfPvAndPayment < 0)) {
204 sumOfPvAndPayment = -sumOfPvAndPayment;
205 currentValueOfPvAndPayment = -currentValueOfPvAndPayment;
207 else if ((sumOfPvAndPayment <= 0) || (currentValueOfPvAndPayment < 0))
208 throw new ArgumentException (Utils.GetResourceString ("Financial_CannotCalculateNPer"));
210 double totalInterestRate = sumOfPvAndPayment / currentValueOfPvAndPayment;
211 return Math.Log (totalInterestRate) / Math.Log (Rate + 1);
214 public static double NPV (double Rate, ref double[] ValueArray)
216 if (ValueArray == null)
217 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidNullValue1", "ValueArray"));
219 double [] arr = ValueArray;
221 throw new ArgumentException (Utils.GetResourceString ("Argument_RankEQOne1", "ValueArray"));
223 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "Rate"));
224 int length = arr.Length;
226 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "ValueArray"));
228 double currentValue = 0;
229 double currentRate = 1;
231 for (int index = 0; index < length; index++) {
232 currentValue = arr [index];
233 currentRate *= (1 + Rate);
234 sum += (currentValue / currentRate);
239 public static double Pmt (double Rate, double NPer, double PV,
240 [Optional, DefaultValue (0)] double FV,
241 [Optional, DefaultValue (0)] DueDate Due)
246 throw new ArgumentException (Utils.GetResourceString ("Argument_InvalidValue1", "NPer"));
248 double totalFutureVal = 0;
249 double geometricSum = 0;
251 totalFutureVal = FV + PV;
254 else if (Due == DueDate.EndOfPeriod) {
255 double totalRate = Math.Pow (Rate + 1, NPer);
256 totalFutureVal = FV + PV * totalRate;
257 geometricSum = (totalRate - 1) / Rate;
259 else if (Due == DueDate.BegOfPeriod) {
260 double totalRate = Math.Pow (Rate + 1, NPer);
261 totalFutureVal = FV + PV * totalRate;
262 geometricSum = ((1 + Rate) * (totalRate - 1)) / Rate;
264 return (totalFutureVal) / geometricSum;
267 public static double PPmt (double Rate, double Per, double NPer, double PV,
268 [Optional, DefaultValue (0)] double FV,
269 [Optional, DefaultValue (0)] DueDate Due)
271 if ((Per <= 0) || (Per >= (NPer + 1)))
272 throw new ArgumentException(Utils.GetResourceString ("PPMT_PerGT0AndLTNPer", "Per"));
273 double interestPayment = IPmt (Rate, Per, NPer, PV, FV, Due);
274 double totalPayment = Pmt (Rate, NPer, PV, FV, Due);
275 return (totalPayment - interestPayment);
278 public static double PV (double Rate, double NPer, double Pmt,
279 [Optional, DefaultValue (0)] double FV,
280 [Optional, DefaultValue (0)] DueDate Due)
284 double currentRate = 1;
286 for (int index = 1; index <= NPer; index++) {
287 currentRate *= (1 + Rate);
288 sum += (Pmt / currentRate);
291 if (Due == DueDate.BegOfPeriod)
293 return sum + FV / currentRate;
296 public static double Rate (double NPer, double Pmt, double PV,
297 [Optional, DefaultValue (0)] double FV,
298 [Optional, DefaultValue (0)] DueDate Due,
299 [Optional, DefaultValue (0.1)] double Guess)
301 double updatedGuess, tmp, origFv, updatedFv;
302 double rateDiff = 0.0;
306 throw new ArgumentException (Utils.GetResourceString ("Rate_NPerMustBeGTZero"));
307 origFv = -Financial.FV (Guess, NPer, Pmt, PV, Due) + FV;
308 updatedGuess = (origFv > 0) ? (Guess / 2) : (Guess * 2);
309 rateDiff = updatedGuess - Guess;
310 updatedFv = -Financial.FV (updatedGuess, NPer, Pmt, PV, Due) + FV;
311 fvDiff = updatedFv - origFv;
312 for (int i = 0; i < 20; i++) {
313 Guess += (updatedGuess > Guess) ? -0.00001 : 0.00001;
314 origFv = -Financial.FV (Guess, NPer, Pmt, PV, Due) + FV;
315 rateDiff = updatedGuess - Guess;
316 fvDiff = updatedFv - origFv;
318 throw new ArgumentException (Utils.GetResourceString ("Financial_CalcDivByZero"));
319 Guess = updatedGuess - (rateDiff * updatedFv / fvDiff);
320 origFv = -Financial.FV (Guess, NPer, Pmt, PV, Due) + FV;
321 if (Math.Abs (origFv) < 0.0000001)
324 Guess = updatedGuess;
330 double origFVAbs = Math.Abs (origFv);
331 double updatedFVAbs = Math.Abs (updatedFv);
332 if ((origFVAbs < 0.0000001) && (updatedFVAbs < 0.0000001))
333 return (origFVAbs < updatedFVAbs) ? Guess : updatedGuess;
334 else if (origFVAbs < 0.0000001)
336 else if (updatedFVAbs < 0.0000001)
339 throw new ArgumentException (Utils.GetResourceString ("Financial_CannotCalculateRate"));
342 public static double SLN (double Cost, double Salvage, double Life)
345 throw new ArgumentException (Utils.GetResourceString ("Financial_LifeNEZero"));
347 return (Cost - Salvage) / Life;
350 public static double SYD (double Cost, double Salvage, double Life, double Period)
353 throw new ArgumentException (Utils.GetResourceString("Financial_ArgGTZero1", "Period"));
354 else if (Salvage < 0)
355 throw new ArgumentException (Utils.GetResourceString("Financial_ArgGEZero1", "Salvage"));
356 else if (Period > Life)
357 throw new ArgumentException (Utils.GetResourceString("Financial_PeriodLELife"));
359 double depreciation = (Cost - Salvage);
360 double sumOfDigits = (Life + 1) * Life / 2;
361 double currentPeriodPart = Life + 1 - Period ;
363 return depreciation * currentPeriodPart / sumOfDigits;