2 * This implementation has been taken from the OpenOffice 1.0, see
3 * functions in scaddins/source/analysis/analysishelper.cxx. Since
4 * then there has been made some Gnumeric type system, glib and the C
5 * language specific changes.
7 * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
9 * Sun has made the contents of this file available subject to the
10 * terms of GNU Lesser General Public License Version 2.1 as
11 * specified in scaddins/source/analysis/analysishelper.cxx revision
12 * 1.35 available in the OpenOffice package.
15 * Copyright: 2000 by Sun Microsystems, Inc.
17 * GNU Lesser General Public License Version 2.1
18 * =============================================
19 * Copyright 2000 by Sun Microsystems, Inc.
20 * 901 San Antonio Road, Palo Alto, CA 94303, USA
22 * This library is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU Lesser General Public
24 * License version 2.1, as published by the Free Software Foundation.
26 * This library is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 * Lesser General Public License for more details.
31 * You should have received a copy of the GNU Lesser General Public
32 * License along with this library; if not, write to the Free Software
33 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
37 #include <gnumeric-config.h>
39 #include <gnm-datetime.h>
46 GetRmz ( gnm_float fZins
, gnm_float fZzr
, gnm_float fBw
, gnm_float fZw
,
52 fRmz
= ( fBw
+ fZw
) / fZzr
;
54 gnm_float fTerm
= gnm_pow ( 1.0 + fZins
, fZzr
);
56 fRmz
= ( fZw
* fZins
/ ( fTerm
- 1.0 ) + fBw
* fZins
/
57 ( 1.0 - 1.0 / fTerm
) ) / ( 1.0 + fZins
);
59 fRmz
= fZw
* fZins
/ ( fTerm
- 1.0 ) + fBw
* fZins
/
60 ( 1.0 - 1.0 / fTerm
);
67 GetZw ( gnm_float fZins
, gnm_float fZzr
, gnm_float fRmz
, gnm_float fBw
,
73 fZw
= fBw
+ fRmz
* fZzr
;
75 gnm_float fTerm
= gnm_pow ( 1.0 + fZins
, fZzr
);
77 fZw
= fBw
* fTerm
+ fRmz
* ( 1.0 + fZins
) *
78 ( fTerm
- 1.0 ) / fZins
;
80 fZw
= fBw
* fTerm
+ fRmz
* ( fTerm
- 1.0 ) / fZins
;
87 Duration (GDate
*nSettle
, GDate
*nMat
, gnm_float fCoup
, gnm_float fYield
,
88 gint nFreq
, gint nBase
, gnm_float fNumOfCoups
)
90 /* gnm_float fYearfrac = yearfrac ( nSettle, nMat, nBase ); */
94 const gnm_float f100
= 100.0;
96 fCoup
*= f100
/ (gnm_float
) nFreq
; /* fCoup is used as cash flow */
100 for ( t
= 1.0 ; t
< fNumOfCoups
; t
++ )
101 fDur
+= t
* ( fCoup
) / gnm_pow ( fYield
, t
);
103 fDur
+= fNumOfCoups
* ( fCoup
+ f100
) / gnm_pow ( fYield
, fNumOfCoups
);
105 for ( t
= 1.0 ; t
< fNumOfCoups
; t
++ )
106 p
+= fCoup
/ gnm_pow ( fYield
, t
);
108 p
+= ( fCoup
+ f100
) / gnm_pow ( fYield
, fNumOfCoups
);
111 fDur
/= (gnm_float
) nFreq
;
116 /***************************************************************************/
119 get_amordegrc (gnm_float fCost
, GDate
*nDate
, GDate
*nFirstPer
,
120 gnm_float fRestVal
, gint nPer
, gnm_float fRate
,
124 gnm_float fAmorCoeff
, fNRate
, fRest
, fUsePer
;
126 #define Round(x,y) (go_rint (x))
128 fUsePer
= 1.0 / fRate
;
132 else if (fUsePer
< 5.0)
134 else if (fUsePer
<= 6.0)
140 fNRate
= Round ( yearfrac( nDate
, nFirstPer
, nBase
) * fRate
*
143 fRest
= fCost
- fRestVal
;
145 for ( n
= 0 ; n
< nPer
; n
++ ) {
146 fNRate
= Round ( fRate
* fCost
, 0 );
150 switch ( nPer
- n
) {
153 return value_new_float (Round ( fCost
* 0.5,
156 return value_new_float (0.0);
162 return value_new_float (fNRate
);
166 /***************************************************************************/
169 get_amorlinc (gnm_float fCost
, GDate
*nDate
, GDate
*nFirstPer
,
170 gnm_float fRestVal
, gint nPer
, gnm_float fRate
, gint nBase
)
172 gnm_float fOneRate
= fCost
* fRate
;
173 gnm_float fCostDelta
= fCost
- fRestVal
;
174 gnm_float f0Rate
= yearfrac ( nDate
, nFirstPer
, nBase
)
176 gint nNumOfFullPeriods
= (fCost
- fRestVal
- f0Rate
) / fOneRate
;
181 else if( nPer
<= nNumOfFullPeriods
)
183 else if( nPer
== nNumOfFullPeriods
+ 1 )
184 result
= fCostDelta
- fOneRate
* nNumOfFullPeriods
- f0Rate
;
188 return value_new_float ( result
);
191 /***************************************************************************/
193 GnmValue
* get_yieldmat (GDate
*nSettle
, GDate
*nMat
, GDate
*nIssue
,
194 gnm_float fRate
, gnm_float fPrice
, gint nBase
)
196 gnm_float fIssMat
= yearfrac ( nIssue
, nMat
, nBase
);
197 gnm_float fIssSet
= yearfrac ( nIssue
, nSettle
, nBase
);
198 gnm_float fSetMat
= yearfrac ( nSettle
, nMat
, nBase
);
199 gnm_float y
= 1.0 + fIssMat
* fRate
;
201 y
/= fPrice
/ 100.0 + fIssSet
* fRate
;
205 return value_new_float ( y
);
208 /***************************************************************************/
211 get_duration (GDate
*nSettle
, GDate
*nMat
, gnm_float fCoup
,
212 gnm_float fYield
, gint nFreq
, gint nBase
,
213 gnm_float fNumOfCoups
)
215 return value_new_float ( Duration (nSettle
, nMat
, fCoup
, fYield
, nFreq
,
216 nBase
, fNumOfCoups
) );
219 /***************************************************************************/
222 get_mduration (GDate
*nSettle
, GDate
*nMat
, gnm_float fCoup
,
223 gnm_float fYield
, gint nFreq
, gint nBase
,
224 gnm_float fNumOfCoups
)
226 gnm_float fRet
= Duration (nSettle
, nMat
, fCoup
, fYield
, nFreq
, nBase
,
229 fRet
/= 1.0 + ( fYield
/ (gnm_float
) nFreq
);
231 return value_new_float ( fRet
);
234 /***************************************************************************/
237 get_cumprinc (gnm_float fRate
, gint nNumPeriods
, gnm_float fVal
,
238 gint nStart
, gint nEnd
, gint nPayType
)
240 gnm_float fRmz
, fKapZ
;
243 fRmz
= GetRmz ( fRate
, nNumPeriods
, fVal
, 0.0, nPayType
);
249 fKapZ
= fRmz
+ fVal
* fRate
;
256 for ( i
= nStart
; i
<= nEnd
; i
++ ) {
258 fKapZ
+= fRmz
- ( GetZw ( fRate
, ( i
- 2 ), fRmz
,
259 fVal
, 1 ) - fRmz
) * fRate
;
261 fKapZ
+= fRmz
- GetZw( fRate
, ( i
- 1 ), fRmz
, fVal
,
265 return value_new_float ( fKapZ
);
268 /***************************************************************************/
271 get_cumipmt (gnm_float fRate
, gint nNumPeriods
, gnm_float fVal
,
272 gint nStart
, gint nEnd
, gint nPayType
)
274 gnm_float fRmz
, fZinsZ
;
277 fRmz
= GetRmz ( fRate
, nNumPeriods
, fVal
, 0.0, nPayType
);
288 for ( i
= nStart
; i
<= nEnd
; i
++ ) {
290 fZinsZ
+= GetZw ( fRate
, ( i
- 2 ), fRmz
, fVal
, 1 )
293 fZinsZ
+= GetZw ( fRate
, ( i
- 1 ), fRmz
, fVal
, 0 );
298 return value_new_float ( fZinsZ
);
301 /***************************************************************************/
305 * Original source of the following functions (ScGetGDA, ScInterVDB, and
306 * get_vdb) is the OpenOffice version 1.0, `sc/source/core/tool/interpr2.cxx'.
308 * RCSfile: interpr2.cxx,v
312 * last change: Author: er Date: 2001/03/15 21:31:13
317 ScGetGDA (gnm_float fWert
, gnm_float fRest
, gnm_float fDauer
,
318 gnm_float fPeriode
, gnm_float fFaktor
)
320 gnm_float fGda
, fZins
, fAlterWert
, fNeuerWert
; /* FIXME: translate? */
322 fZins
= fFaktor
/ fDauer
;
330 fAlterWert
= fWert
* gnm_pow (1.0 - fZins
, fPeriode
- 1.0);
331 fNeuerWert
= fWert
* gnm_pow (1.0 - fZins
, fPeriode
);
333 if (fNeuerWert
< fRest
)
334 fGda
= fAlterWert
- fRest
;
336 fGda
= fAlterWert
- fNeuerWert
;
343 ScInterVDB (gnm_float cost
, gnm_float salvage
, gnm_float life
,
344 gnm_float life1
, gnm_float period
, gnm_float factor
)
347 gnm_float fIntEnd
= gnm_ceil (period
);
348 int nLoopEnd
= fIntEnd
;
350 gnm_float fTerm
, fLia
;
351 gnm_float fRestwert
= cost
- salvage
;
352 gboolean bNowLia
= FALSE
;
358 for ( i
= 1; i
<= nLoopEnd
; i
++ ) {
360 fGda
= ScGetGDA (cost
, salvage
, life
, i
, factor
);
361 fLia
= fRestwert
/ (life1
- (gnm_float
) (i
- 1));
374 fTerm
*= ( period
+ 1.0 - fIntEnd
);
382 get_vdb (gnm_float cost
, gnm_float salvage
, gnm_float life
,
383 gnm_float start_period
, gnm_float end_period
, gnm_float factor
,
387 gnm_float fIntStart
= gnm_floor (start_period
);
388 gnm_float fIntEnd
= gnm_ceil (end_period
);
393 int i
, nLoopStart
, nLoopEnd
;
395 if (fIntEnd
> G_MAXINT
||
396 fIntEnd
- fIntStart
> 10000 /* arbitrary */)
397 return value_new_error_VALUE (NULL
);
399 nLoopStart
= (int) fIntStart
;
400 nLoopEnd
= (int) fIntEnd
;
401 for (i
= nLoopStart
+ 1; i
<= nLoopEnd
; i
++) {
404 fTerm
= ScGetGDA (cost
, salvage
, life
, i
, factor
);
405 if ( i
== nLoopStart
+1 )
406 fTerm
*= ( MIN( end_period
, fIntStart
+ 1.0 )
408 else if ( i
== nLoopEnd
)
409 fTerm
*= ( end_period
+ 1.0 - fIntEnd
);
414 double fIntEnd
= gnm_ceil (end_period
);
416 if (start_period
> fIntStart
) {
417 // First period is partial. Calculate the excess as
418 // the pro-rata value of the first period as-if it
420 double tempcost
= cost
-
421 ScInterVDB( cost
, salvage
, life
, life
, fIntStart
, factor
);
422 fPart
+= (start_period
- fIntStart
) *
423 ScInterVDB( tempcost
, salvage
, life
, life
- fIntStart
,
427 if (end_period
< fIntEnd
) {
428 // Last period is partial. Calculate the excess as
429 // the pro-rata value of the last period as-if it
431 double em1
= fIntEnd
- 1; // Start of last period
432 double tempcost
= cost
-
433 ScInterVDB (cost
, salvage
, life
, life
, em1
, factor
);
434 fPart
+= (fIntEnd
- end_period
) *
435 ScInterVDB (tempcost
, salvage
, life
, life
- em1
,
439 cost
-= ScInterVDB (cost
, salvage
, life
, life
, fIntStart
, factor
);
440 fVdb
= ScInterVDB (cost
, salvage
, life
, life
- fIntStart
,
441 fIntEnd
- fIntStart
, factor
);
444 return value_new_float (fVdb
);