5 // Chris J Breisch (cjbreisch@altavista.net)
7 // (C) 2002 Chris J Breisch
11 // Copyright (c) 2002-2003 Mainsoft Corporation.
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System
.Runtime
.InteropServices
;
36 using Microsoft
.VisualBasic
.CompilerServices
;
38 namespace Microsoft
.VisualBasic
41 sealed public class Financial
{
44 private Financial() {} // prevent public default constructor
47 public static double DDB (double Cost
, double Salvage
, double Life
, double Period
,
48 [Optional
, __DefaultArgumentValue(2)] double Factor
)
50 // LAMESPEC: MSDN says Life and Factor only throws exception if < 0, but Implementation throws exception if <= 0
57 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "Factor"));
59 return (((Cost
- Salvage
) * Factor
) / Life
) * Period
;
62 public static double FV (double Rate
, double NPer
, double Pmt
,
63 [Optional
, __DefaultArgumentValue(0)] double PV
,
64 [Optional
, __DefaultArgumentValue(0)] DueDate Due
)
68 double currentRate
= Math
.Pow (Rate
+ 1, NPer
);
72 sum
= Pmt
* ((currentRate
- 1) / Rate
);
76 if (Due
== DueDate
.BegOfPeriod
)
79 return PV
* currentRate
+ sum
;
82 public static double IPmt (double Rate
, double Per
, double NPer
, double PV
,
83 [Optional
, __DefaultArgumentValue(0)] double FV
,
84 [Optional
, __DefaultArgumentValue(0)] DueDate Due
)
86 double totalFutureVal
;
87 double totalPaymentValue
;
88 double numberOfPeriods
;
90 if ((Per
<= 0) || (Per
>= (NPer
+ 1)))
91 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "Per"));
92 if ((Due
== DueDate
.BegOfPeriod
) && (Per
== 1))
95 totalPaymentValue
= Pmt (Rate
, NPer
, PV
, FV
, Due
);
96 if (Due
== DueDate
.BegOfPeriod
)
97 PV
= (PV
+ totalPaymentValue
);
99 numberOfPeriods
= Per
- ((int)Due
) - 1;
101 Financial
.FV (Rate
, numberOfPeriods
, totalPaymentValue
, PV
, DueDate
.EndOfPeriod
);
103 return (totalFutureVal
* Rate
);
106 public static double IRR (ref double[] ValueArray
, [Optional
, __DefaultArgumentValue(0.1)] double Guess
)
108 double origPV
, updatedPV
, updateGuess
, tmp
;
109 double rateDiff
= 0.0;
113 // MS.NET 2.0 docs say that Guess may not be <= -1
115 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "Guess"));
117 length
= ValueArray
.GetLength(0);
120 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "ValueArray"));
123 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "ValueArray"));
125 origPV
= NPV (Guess
, ref ValueArray
);
126 updateGuess
= (origPV
> 0) ? Guess
+ 0.00001 : Guess
- 0.00001;
128 if (updateGuess
< -1)
129 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "Rate"));
131 rateDiff
= updateGuess
- Guess
;
132 updatedPV
= NPV (updateGuess
, ref ValueArray
);
133 pvDiff
= updatedPV
- origPV
;
134 for (int i
= 0; i
< 20; i
++) {
135 Guess
= (updateGuess
> Guess
) ? (Guess
- 0.00001) : (Guess
+ 0.00001);
136 origPV
= NPV (Guess
, ref ValueArray
);
137 rateDiff
= updateGuess
- Guess
;
138 pvDiff
= updatedPV
- origPV
;
140 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue"));
141 Guess
= updateGuess
- (rateDiff
* updatedPV
/ pvDiff
);
144 origPV
= NPV (Guess
, ref ValueArray
);
145 if ((Math
.Abs (origPV
) < 0.0000001) && (Math
.Abs (rateDiff
) < 0.00001))
155 double origPVAbs
= Math
.Abs (origPV
);
156 double updatedPVAbs
= Math
.Abs (updatedPV
);
157 if ((origPVAbs
< 0.0000001) && (updatedPVAbs
< 0.0000001))
158 return (origPVAbs
< updatedPVAbs
) ? Guess
: updateGuess
;
159 else if (origPVAbs
< 0.0000001)
161 else if (updatedPVAbs
< 0.0000001)
164 throw new ArgumentException(Utils
.GetResourceString ("Argument_InvalidValue"));
167 public static double MIRR (ref double[] ValueArray
, double FinanceRate
, double ReinvestRate
)
169 double [] array
= ValueArray
;
171 double assetsVal
= 0;
172 double currentLoanRate
= 1;
173 double currentAssetsRate
= 1;
174 double totalInterestRate
= 0;
177 throw new ArgumentException (Utils
.GetResourceString ("Argument_RankEQOne1", "ValueArray"));
178 else if (FinanceRate
== -1)
179 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "FinanceRate"));
180 else if (ReinvestRate
== -1)
181 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "ReinvestRate"));
183 arrayLength
= array
.Length
;
185 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "ValueArray"));
187 for (int i
= 0; i
< arrayLength
; i
++) {
188 currentLoanRate
*= (1 + FinanceRate
);
189 currentAssetsRate
*= (1 + ReinvestRate
);
191 loansVal
+= (array
[i
] / currentLoanRate
);
192 else if (array
[i
] > 0)
193 assetsVal
+= (array
[i
] / currentAssetsRate
);
197 throw new DivideByZeroException (Utils
.GetResourceString ("Financial_CalcDivByZero"));
200 ((-assetsVal
* Math
.Pow (ReinvestRate
+ 1, arrayLength
))
201 / (loansVal
* (FinanceRate
+ 1)));
202 if (totalInterestRate
< 0)
203 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue"));
205 return (Math
.Pow (totalInterestRate
, 1 / (double) (arrayLength
- 1))) - 1;
208 public static double NPer (double Rate
, double Pmt
, double PV
,
209 [Optional
, __DefaultArgumentValue(0)] double FV
,
210 [Optional
, __DefaultArgumentValue(0)] DueDate Due
)
212 double totalIncomeFromFlow
, sumOfPvAndPayment
, currentValueOfPvAndPayment
;
213 if (Rate
== 0 && Pmt
== 0)
214 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "Pmt"));
216 return (- (PV
+ FV
) / Pmt
);
217 // MainSoft had Rate < -1, but MS.NET 2.0 Doc says Rate should not be <= -1
219 throw new ArgumentException(Utils
.GetResourceString ("Argument_InvalidValue1", "Rate"));
220 totalIncomeFromFlow
= (Pmt
/ Rate
);
221 if (Due
== DueDate
.BegOfPeriod
)
222 totalIncomeFromFlow
*= (1 + Rate
);
224 sumOfPvAndPayment
= (-FV
+ totalIncomeFromFlow
);
225 currentValueOfPvAndPayment
= (PV
+ totalIncomeFromFlow
);
226 if ((sumOfPvAndPayment
< 0) && (currentValueOfPvAndPayment
< 0)) {
227 sumOfPvAndPayment
= -sumOfPvAndPayment
;
228 currentValueOfPvAndPayment
= -currentValueOfPvAndPayment
;
230 else if ((sumOfPvAndPayment
<= 0) || (currentValueOfPvAndPayment
< 0))
231 throw new ArgumentException (Utils
.GetResourceString ("Financial_CannotCalculateNPer"));
233 double totalInterestRate
= sumOfPvAndPayment
/ currentValueOfPvAndPayment
;
234 return Math
.Log (totalInterestRate
) / Math
.Log (Rate
+ 1);
237 public static double NPV (double Rate
, ref double[] ValueArray
)
239 if (ValueArray
== null)
240 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidNullValue1", "ValueArray"));
242 double [] arr
= ValueArray
;
244 throw new ArgumentException (Utils
.GetResourceString ("Argument_RankEQOne1", "ValueArray"));
246 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "Rate"));
247 int length
= arr
.Length
;
249 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "ValueArray"));
251 double currentValue
= 0;
252 double currentRate
= 1;
254 for (int index
= 0; index
< length
; index
++) {
255 currentValue
= arr
[index
];
256 currentRate
*= (1 + Rate
);
257 sum
+= (currentValue
/ currentRate
);
262 public static double Pmt (double Rate
, double NPer
, double PV
,
263 [Optional
, __DefaultArgumentValue(0)] double FV
,
264 [Optional
, __DefaultArgumentValue(0)] DueDate Due
)
269 throw new ArgumentException (Utils
.GetResourceString ("Argument_InvalidValue1", "NPer"));
271 double totalFutureVal
= 0;
272 double geometricSum
= 0;
274 totalFutureVal
= FV
+ PV
;
277 else if (Due
== DueDate
.EndOfPeriod
) {
278 double totalRate
= Math
.Pow (Rate
+ 1, NPer
);
279 totalFutureVal
= FV
+ PV
* totalRate
;
280 geometricSum
= (totalRate
- 1) / Rate
;
282 else if (Due
== DueDate
.BegOfPeriod
) {
283 double totalRate
= Math
.Pow (Rate
+ 1, NPer
);
284 totalFutureVal
= FV
+ PV
* totalRate
;
285 geometricSum
= ((1 + Rate
) * (totalRate
- 1)) / Rate
;
287 return (totalFutureVal
) / geometricSum
;
290 public static double PPmt (double Rate
, double Per
, double NPer
, double PV
,
291 [Optional
, __DefaultArgumentValue(0)] double FV
,
292 [Optional
, __DefaultArgumentValue(0)] DueDate Due
)
294 if ((Per
<= 0) || (Per
>= (NPer
+ 1)))
295 throw new ArgumentException(Utils
.GetResourceString ("PPMT_PerGT0AndLTNPer", "Per"));
296 double interestPayment
= IPmt (Rate
, Per
, NPer
, PV
, FV
, Due
);
297 double totalPayment
= Pmt (Rate
, NPer
, PV
, FV
, Due
);
298 return (totalPayment
- interestPayment
);
301 public static double PV (double Rate
, double NPer
, double Pmt
,
302 [Optional
, __DefaultArgumentValue(0)] double FV
,
303 [Optional
, __DefaultArgumentValue(0)] DueDate Due
)
307 double currentRate
= 1;
309 for (int index
= 1; index
<= NPer
; index
++) {
310 currentRate
*= (1 + Rate
);
311 sum
+= (Pmt
/ currentRate
);
314 if (Due
== DueDate
.BegOfPeriod
)
316 return sum
+ FV
/ currentRate
;
319 public static double Rate (double NPer
, double Pmt
, double PV
,
320 [Optional
, __DefaultArgumentValue(0)] double FV
,
321 [Optional
, __DefaultArgumentValue(0)] DueDate Due
,
322 [Optional
, __DefaultArgumentValue(0.1)] double Guess
)
324 double updatedGuess
, tmp
, origFv
, updatedFv
;
325 double rateDiff
= 0.0;
329 throw new ArgumentException (Utils
.GetResourceString ("Rate_NPerMustBeGTZero"));
330 origFv
= -Financial
.FV (Guess
, NPer
, Pmt
, PV
, Due
) + FV
;
331 updatedGuess
= (origFv
> 0) ? (Guess
/ 2) : (Guess
* 2);
332 rateDiff
= updatedGuess
- Guess
;
333 updatedFv
= -Financial
.FV (updatedGuess
, NPer
, Pmt
, PV
, Due
) + FV
;
334 fvDiff
= updatedFv
- origFv
;
335 for (int i
= 0; i
< 20; i
++) {
336 Guess
+= (updatedGuess
> Guess
) ? -0.00001 : 0.00001;
337 origFv
= -Financial
.FV (Guess
, NPer
, Pmt
, PV
, Due
) + FV
;
338 rateDiff
= updatedGuess
- Guess
;
339 fvDiff
= updatedFv
- origFv
;
341 throw new ArgumentException (Utils
.GetResourceString ("Financial_CalcDivByZero"));
342 Guess
= updatedGuess
- (rateDiff
* updatedFv
/ fvDiff
);
343 origFv
= -Financial
.FV (Guess
, NPer
, Pmt
, PV
, Due
) + FV
;
344 if (Math
.Abs (origFv
) < 0.0000001)
347 Guess
= updatedGuess
;
353 double origFVAbs
= Math
.Abs (origFv
);
354 double updatedFVAbs
= Math
.Abs (updatedFv
);
355 if ((origFVAbs
< 0.0000001) && (updatedFVAbs
< 0.0000001))
356 return (origFVAbs
< updatedFVAbs
) ? Guess
: updatedGuess
;
357 else if (origFVAbs
< 0.0000001)
359 else if (updatedFVAbs
< 0.0000001)
362 throw new ArgumentException (Utils
.GetResourceString ("Financial_CannotCalculateRate"));
365 public static double SLN (double Cost
, double Salvage
, double Life
)
368 throw new ArgumentException (Utils
.GetResourceString ("Financial_LifeNEZero"));
370 return (Cost
- Salvage
) / Life
;
373 public static double SYD (double Cost
, double Salvage
, double Life
, double Period
)
376 throw new ArgumentException (Utils
.GetResourceString("Financial_ArgGTZero1", "Period"));
377 else if (Salvage
< 0)
378 throw new ArgumentException (Utils
.GetResourceString("Financial_ArgGEZero1", "Salvage"));
379 else if (Period
> Life
)
380 throw new ArgumentException (Utils
.GetResourceString("Financial_PeriodLELife"));
382 double depreciation
= (Cost
- Salvage
);
383 double sumOfDigits
= (Life
+ 1) * Life
/ 2;
384 double currentPeriodPart
= Life
+ 1 - Period
;
386 return depreciation
* currentPeriodPart
/ sumOfDigits
;