kspread Library API Documentation

kspread_functions_financial.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998-2002 The KSpread Team
00003                            www.koffice.org/kspread
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 */
00020 
00021 // built-in financial functions
00022 
00023 #include <stdlib.h>
00024 #include <math.h>
00025 #include <float.h>
00026 
00027 #include <kdebug.h>
00028 
00029 #include <koscript_parser.h>
00030 #include <koscript_util.h>
00031 #include <koscript_func.h>
00032 #include <koscript_synext.h>
00033 
00034 #include "kspread_functions.h"
00035 #include "kspread_functions_helper.h"
00036 #include "kspread_util.h"
00037 
00038 
00039 // prototypes (sorted)
00040 bool kspreadfunc_accrint( KSContext& context );
00041 bool kspreadfunc_accrintm( KSContext& context );
00042 bool kspreadfunc_compound( KSContext& context );
00043 bool kspreadfunc_continuous( KSContext& context );
00044 bool kspreadfunc_coupnum( KSContext& context );
00045 bool kspreadfunc_db( KSContext& context );
00046 bool kspreadfunc_ddb( KSContext& context );
00047 bool kspreadfunc_disc( KSContext& context );
00048 bool kspreadfunc_dollarde( KSContext& context );
00049 bool kspreadfunc_dollarfr( KSContext& context );
00050 bool kspreadfunc_duration( KSContext& context );
00051 bool kspreadfunc_effective( KSContext& context );
00052 bool kspreadfunc_euro( KSContext& context );
00053 bool kspreadfunc_fv( KSContext& context );
00054 bool kspreadfunc_fv_annuity( KSContext& context );
00055 bool kspreadfunc_intrate( KSContext& context );
00056 bool kspreadfunc_ipmt( KSContext& context );
00057 bool kspreadfunc_ispmt( KSContext& context );
00058 bool kspreadfunc_level_coupon( KSContext& context );
00059 bool kspreadfunc_nominal( KSContext& context );
00060 bool kspreadfunc_nper( KSContext& context );
00061 bool kspreadfunc_pmt( KSContext& context );
00062 bool kspreadfunc_ppmt( KSContext& context );
00063 bool kspreadfunc_pv( KSContext& context );
00064 bool kspreadfunc_pv_annuity( KSContext& context );
00065 bool kspreadfunc_received( KSContext& context );
00066 bool kspreadfunc_sln( KSContext& context );
00067 bool kspreadfunc_syd( KSContext& context );
00068 bool kspreadfunc_tbilleq( KSContext& context );
00069 bool kspreadfunc_tbillprice( KSContext& context );
00070 bool kspreadfunc_tbillyield( KSContext& context );
00071 bool kspreadfunc_zero_coupon( KSContext& context );
00072 
00073 // registers all financial functions
00074 void KSpreadRegisterFinancialFunctions()
00075 {
00076   KSpreadFunctionRepository* repo = KSpreadFunctionRepository::self();
00077 
00078   repo->registerFunction( "ACCRINT", kspreadfunc_accrint );
00079   repo->registerFunction( "ACCRINTM", kspreadfunc_accrintm );
00080   repo->registerFunction( "COMPOUND", kspreadfunc_compound );
00081   repo->registerFunction( "CONTINUOUS", kspreadfunc_continuous );
00082   repo->registerFunction( "COUPNUM", kspreadfunc_coupnum );
00083   repo->registerFunction( "DB", kspreadfunc_db );
00084   repo->registerFunction( "DDB", kspreadfunc_ddb );
00085   repo->registerFunction( "DISC", kspreadfunc_disc );
00086   repo->registerFunction( "DOLLARDE", kspreadfunc_dollarde );
00087   repo->registerFunction( "DOLLARFR", kspreadfunc_dollarfr );
00088   repo->registerFunction( "DURATION", kspreadfunc_duration );
00089   repo->registerFunction( "EFFECT", kspreadfunc_effective );
00090   repo->registerFunction( "EFFECTIVE", kspreadfunc_effective );
00091   repo->registerFunction( "EURO", kspreadfunc_euro );  // KSpread-specific, Gnumeric-compatible
00092   repo->registerFunction( "FV", kspreadfunc_fv );
00093   repo->registerFunction( "FV_ANNUITY", kspreadfunc_fv_annuity );
00094   repo->registerFunction( "INTRATE", kspreadfunc_intrate );
00095   repo->registerFunction( "IPMT", kspreadfunc_ipmt );
00096   repo->registerFunction( "ISPMT", kspreadfunc_ispmt );
00097   repo->registerFunction( "LEVEL_COUPON", kspreadfunc_level_coupon );
00098   repo->registerFunction( "NOMINAL", kspreadfunc_nominal );
00099   repo->registerFunction( "NPER", kspreadfunc_nper );
00100   repo->registerFunction( "PMT", kspreadfunc_pmt );
00101   repo->registerFunction( "PPMT", kspreadfunc_ppmt );
00102   repo->registerFunction( "PV", kspreadfunc_pv );
00103   repo->registerFunction( "PV_ANNUITY", kspreadfunc_pv_annuity );
00104   repo->registerFunction( "RECEIVED", kspreadfunc_received );
00105   repo->registerFunction( "SLN", kspreadfunc_sln );
00106   repo->registerFunction( "SYD", kspreadfunc_syd );
00107   repo->registerFunction( "TBILLEQ", kspreadfunc_tbilleq );
00108   repo->registerFunction( "TBILLPRICE", kspreadfunc_tbillprice );
00109   repo->registerFunction( "TBILLYIELD", kspreadfunc_tbillyield );
00110   repo->registerFunction( "ZERO_COUPON", kspreadfunc_zero_coupon );
00111 }
00112 
00113 static double getPay( double rate, double nper, double pv, double fv, int type )
00114 {
00115   double pvif, fvifa;
00116 
00117   pvif  = ( pow( 1 + rate, nper ) );
00118   fvifa = ( pow( 1 + rate, nper ) - 1 ) / rate;
00119 
00120   return ( ( -pv * pvif - fv ) / ( ( 1.0 + rate * type ) * fvifa ) );
00121 }
00122 
00123 static double getPrinc( double start, double pay,
00124                         double rate, double period )
00125 {
00126   return ( start * pow( 1.0 + rate, period) + pay
00127            * ( ( pow( 1 + rate, period ) - 1 ) / rate ) );
00128 }
00129 
00130 static bool getCoupParameter( KSContext & context, QString const & fName, QDate & settlement,
00131                               QDate & maturity, int & frequency, int & basis, bool & eom )
00132 {
00133   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00134 
00135   if ( !KSUtil::checkArgumentsCount( context, 5, fName, true ) )
00136   {
00137     if ( !KSUtil::checkArgumentsCount( context, 4, fName, true ) )
00138     {
00139       if ( !KSUtil::checkArgumentsCount( context, 3, fName, true ) )
00140         return false;
00141     }
00142     else
00143     {
00144       if ( !KSUtil::checkType( context, args[3], KSValue::IntType, true ) )
00145         return false;
00146       basis = args[3]->intValue();
00147     }
00148   }
00149   else
00150   {
00151     if ( !KSUtil::checkType( context, args[3], KSValue::IntType, true ) )
00152       return false;
00153     if ( !KSUtil::checkType( context, args[4], KSValue::BoolType, true ) )
00154       return false;
00155 
00156     basis = args[3]->intValue();
00157     eom   = args[4]->boolValue();
00158   }
00159 
00160   if ( !getDate( context, args[0], settlement ) )
00161     return false;
00162 
00163   if ( !getDate( context, args[1], maturity ) )
00164     return false;
00165 
00166   if ( !KSUtil::checkType( context, args[2], KSValue::IntType, true ) )
00167     return false;
00168 
00169   frequency = args[2]->intValue();
00170 
00171   if (basis < 0 || basis > 5 || ( frequency == 0 ) || ( 12 % frequency != 0 )
00172       || settlement.daysTo( maturity ) <= 0)
00173     return false;
00174 
00175   return true;
00176 }
00177 
00178 // Function: COUPNUM - taken from GNUMERIC
00179 bool kspreadfunc_coupnum( KSContext & context )
00180 {
00181   QDate settlement;
00182   QDate maturity;
00183   int   frequency;
00184   int   basis = 0;
00185   bool  eom   = true;
00186 
00187   if ( !getCoupParameter( context, "COUPNUM", settlement, maturity,
00188                           frequency, basis, eom ) )
00189     return false;
00190 
00191   double result;
00192   QDate cDate( maturity );
00193 
00194   int months = maturity.month() - settlement.month()
00195     + 12 * ( maturity.year() - settlement.year() );
00196 
00197   subMonths( cDate, months );
00198 
00199   if ( eom && maturity.daysInMonth() == maturity.day() )
00200   {
00201     while( cDate.daysInMonth() != cDate.day() )
00202       cDate.addDays( 1 );
00203   }
00204 
00205   if ( settlement.day() >= cDate.day() )
00206     --months;
00207 
00208   result = ( 1 + months / ( 12 / frequency ) );
00209 
00210   context.setValue( new KSValue( result ) );
00211   return true;
00212 }
00213 
00214 // Function: ACCRINT
00215 bool kspreadfunc_accrint( KSContext& context )
00216 {
00217   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00218 
00219   int basis = 0;
00220 
00221   if ( !KSUtil::checkArgumentsCount( context, 7, "ACCRINT", true ) )
00222   {
00223     if ( !KSUtil::checkArgumentsCount( context, 6, "ACCRINT", true ) )
00224       return false;
00225   }
00226   else
00227   {
00228     if ( !KSUtil::checkType( context, args[6], KSValue::IntType, true ) )
00229       return false;
00230 
00231     basis = args[6]->intValue();
00232   }
00233 
00234   QDate maturity;
00235   QDate firstInterest;
00236   QDate settlement;
00237   double rate, par;
00238   double frequency;
00239 
00240   if ( !getDate( context, args[0], maturity ) )
00241     return false;
00242 
00243   if ( !getDate( context, args[1], firstInterest ) )
00244     return false;
00245 
00246   if ( !getDate( context, args[2], settlement ) )
00247     return false;
00248 
00249   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00250     return false;
00251 
00252   if ( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
00253     return false;
00254 
00255   if ( !KSUtil::checkType( context, args[5], KSValue::DoubleType, true ) )
00256     return false;
00257 
00258   rate      = args[3]->doubleValue();
00259   par       = args[4]->doubleValue();
00260   frequency = (int) args[5]->doubleValue();
00261 
00262   if ( basis < 0 || basis > 4 || ( frequency == 0 ) || ( 12 % (int) frequency != 0 ) )
00263     return false;
00264 
00265   if ( ( settlement.daysTo( firstInterest ) < 0 )
00266        || ( firstInterest.daysTo( maturity ) > 0 ) )
00267     return false;
00268 
00269   double d = daysBetweenDates( maturity, settlement, basis );
00270   double y = daysPerYear( maturity, basis );
00271 
00272   if ( d < 0 || y <= 0 || par <= 0 || rate <= 0 )
00273     return false;
00274 
00275   double coeff = par * rate / frequency;
00276   double n = d / y;
00277 
00278   context.setValue( new KSValue( coeff * frequency * n ) );
00279   return true;
00280 }
00281 
00282 // Function: ACCRINTM
00283 bool kspreadfunc_accrintm( KSContext& context )
00284 {
00285   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00286 
00287   int basis  = 0;
00288   double par = 1000;
00289 
00290   if ( !KSUtil::checkArgumentsCount( context, 5, "ACCRINTM", true ) )
00291   {
00292     if ( !KSUtil::checkArgumentsCount( context, 4, "ACCRINTM", true ) )
00293     {
00294       if ( !KSUtil::checkArgumentsCount( context, 3, "ACCRINTM", true ) )
00295         return false;
00296     }
00297     else
00298     {
00299       if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00300         return false;
00301 
00302       par   = args[3]->doubleValue();
00303     }
00304   }
00305   else
00306   {
00307     if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00308       return false;
00309     if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
00310       return false;
00311 
00312     par   = args[3]->doubleValue();
00313     basis = args[4]->intValue();
00314   }
00315 
00316   QDate issue;
00317   QDate maturity;
00318   double rate;
00319 
00320   if ( !getDate( context, args[0], issue ) )
00321     return false;
00322 
00323   if ( !getDate( context, args[1], maturity ) )
00324     return false;
00325 
00326   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00327     return false;
00328 
00329   rate = args[2]->doubleValue();
00330 
00331   double d = daysBetweenDates( issue, maturity, basis );
00332   double y = daysPerYear( issue, basis );
00333 
00334   if ( d < 0 || y <= 0 || par <= 0 || rate <= 0 || basis < 0 || basis > 4 )
00335     return false;
00336 
00337   context.setValue( new KSValue( par * rate * d / y ) );
00338   return true;
00339 }
00340 
00341 // Function: DISC
00342 bool kspreadfunc_disc( KSContext& context )
00343 {
00344   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00345 
00346   int basis = 0;
00347 
00348   if ( !KSUtil::checkArgumentsCount( context, 5, "DISC", true ) )
00349   {
00350     if ( !KSUtil::checkArgumentsCount( context, 4, "DISC", true ) )
00351       return false;
00352   }
00353   else
00354   {
00355     if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
00356       return false;
00357 
00358     basis = args[4]->intValue();
00359   }
00360 
00361   QDate settlement;
00362   QDate maturity;
00363 
00364   if ( !getDate( context, args[0], settlement ) )
00365     return false;
00366 
00367   if ( !getDate( context, args[1], maturity ) )
00368     return false;
00369 
00370   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00371     return false;
00372 
00373   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00374     return false;
00375 
00376   double par    = args[2]->doubleValue();
00377   double redemp = args[3]->doubleValue();
00378 
00379   double y = daysPerYear( settlement, basis );
00380   double d = daysBetweenDates( settlement, maturity, basis );
00381 
00382   if ( y <= 0 || d <= 0 || basis < 0 || basis > 4 || redemp == 0 )
00383     return false;
00384 
00385   context.setValue( new KSValue( ( redemp - par ) / redemp * ( y / d ) ) );
00386   return true;
00387 }
00388 
00389 
00390 // Function: TBILLPRICE
00391 bool kspreadfunc_tbillprice( KSContext& context )
00392 {
00393   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00394 
00395   if ( !KSUtil::checkArgumentsCount( context, 3, "TBILLPRICE", true ) )
00396     return false;
00397 
00398   QDate settlement;
00399   QDate maturity;
00400   double discount;
00401 
00402   if ( !getDate( context, args[0], settlement ) )
00403     return false;
00404 
00405   if ( !getDate( context, args[1], maturity ) )
00406     return false;
00407 
00408   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00409     return false;
00410 
00411   discount = args[2]->doubleValue();
00412 
00413   double days = settlement.daysTo( maturity );
00414 
00415   if ( settlement > maturity || discount < 0 || days > 265 )
00416     return false;
00417 
00418   context.setValue( new KSValue( 100 * ( 1.0 - ( discount * days ) / 360.0 ) ) );
00419   return true;
00420 }
00421 
00422 // Function: TBILLYIELD
00423 bool kspreadfunc_tbillyield( KSContext& context )
00424 {
00425   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00426 
00427   if ( !KSUtil::checkArgumentsCount( context, 3, "TBILLYIELD", true ) )
00428     return false;
00429 
00430   QDate settlement;
00431   QDate maturity;
00432   double rate;
00433 
00434   if ( !getDate( context, args[0], settlement ) )
00435     return false;
00436 
00437   if ( !getDate( context, args[1], maturity ) )
00438     return false;
00439 
00440   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00441     return false;
00442 
00443   rate = args[2]->doubleValue();
00444 
00445   double days = settlement.daysTo( maturity );
00446 
00447   if ( settlement > maturity || rate <= 0 || days > 265 )
00448     return false;
00449 
00450   context.setValue( new KSValue( ( 100.0 - rate ) / rate * ( 360.0 / days ) ) );
00451   return true;
00452 }
00453 
00454 // Function: TBILLEQ
00455 bool kspreadfunc_tbilleq( KSContext& context )
00456 {
00457   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00458 
00459   if ( !KSUtil::checkArgumentsCount( context, 3, "TBILLEQ", true ) )
00460     return false;
00461 
00462   QDate settlement;
00463   QDate maturity;
00464   double discount;
00465 
00466   if ( !getDate( context, args[0], settlement ) )
00467     return false;
00468 
00469   if ( !getDate( context, args[1], maturity ) )
00470     return false;
00471 
00472   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00473     return false;
00474 
00475   discount = args[2]->doubleValue();
00476 
00477   double days = settlement.daysTo( maturity );
00478 
00479   if ( settlement > maturity || discount < 0 || days > 265 )
00480     return false;
00481 
00482   double divisor = 360.0 - discount * days;
00483 
00484   if ( divisor == 0 )
00485     return false;
00486 
00487   context.setValue( new KSValue( 365.0 * discount / divisor ) );
00488   return true;
00489 }
00490 
00491 // Function: RECEIVED
00492 bool kspreadfunc_received( KSContext& context )
00493 {
00494   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00495 
00496   int basis = 0;
00497 
00498   if ( !KSUtil::checkArgumentsCount( context, 5, "RECEIVED", true ) )
00499   {
00500     if ( !KSUtil::checkArgumentsCount( context, 4, "RECEIVED", true ) )
00501       return false;
00502   }
00503   else
00504   {
00505     if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
00506       return false;
00507 
00508     basis = args[4]->intValue();
00509   }
00510 
00511   QDate settlement;
00512   QDate maturity;
00513 
00514   if ( !getDate( context, args[0], settlement ) )
00515     return false;
00516 
00517   if ( !getDate( context, args[1], maturity ) )
00518     return false;
00519 
00520   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00521     return false;
00522 
00523   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00524     return false;
00525 
00526   double investment = args[2]->doubleValue();
00527   double discount   = args[3]->doubleValue();
00528 
00529   double d = daysBetweenDates( settlement, maturity, basis );
00530   double y = daysPerYear( settlement, basis );
00531 
00532   if ( d <= 0 || y <= 0 || basis < 0 || basis > 4 )
00533     return false;
00534 
00535   double x = 1.0 - ( discount * d / y );
00536 
00537   if ( x == 0 )
00538     return false;
00539 
00540   context.setValue( new KSValue( investment / x ) );
00541   return true;
00542 }
00543 
00544 // Function: DOLLARDE
00545 bool kspreadfunc_dollarde( KSContext& context )
00546 {
00547   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00548 
00549   if ( !KSUtil::checkArgumentsCount( context, 2, "DOLLARDE", true ) )
00550     return false;
00551 
00552   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00553     return false;
00554 
00555   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
00556     return false;
00557 
00558   double d = args[0]->doubleValue();
00559   int f = (int) args[1]->intValue();
00560 
00561   if ( f <= 0 )
00562     return false;
00563 
00564   int tmp = f;
00565   int n = 0;
00566   while ( tmp > 0 )
00567   {
00568     tmp /= 10;
00569     ++n;
00570   }
00571 
00572   double fl = floor( d );
00573   double r  = d - fl;
00574 
00575   context.setValue( new KSValue( fl + ( r * pow( 10.0, n ) / (double) f ) ) );
00576   return true;
00577 }
00578 
00579 // Function: DOLLARFR
00580 bool kspreadfunc_dollarfr( KSContext& context )
00581 {
00582   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00583 
00584   if ( !KSUtil::checkArgumentsCount( context, 2, "DOLLARFR", true ) )
00585     return false;
00586 
00587   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00588     return false;
00589 
00590   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
00591     return false;
00592 
00593   double d = args[0]->doubleValue();
00594   int f = (int) args[1]->intValue();
00595 
00596   if ( f <= 0 )
00597     return false;
00598 
00599   int tmp = f;
00600   int n = 0;
00601   while ( tmp > 0 )
00602   {
00603     tmp /= 10;
00604     ++n;
00605   }
00606 
00607   double fl = floor( d );
00608   double r  = d - fl;
00609 
00610   context.setValue( new KSValue( fl + ( ( r * (double) f ) / pow( 10.0, n ) ) ) );
00611   return true;
00612 }
00613 
00614 // Function: INTRATE
00615 bool kspreadfunc_intrate( KSContext& context )
00616 {
00617   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00618 
00619   int basis = 0;
00620 
00621   if ( !KSUtil::checkArgumentsCount( context, 5, "INTRATE", true ) )
00622   {
00623     if ( !KSUtil::checkArgumentsCount( context, 4, "INTRATE", true ) )
00624       return false;
00625   }
00626   else
00627   {
00628     if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
00629       return false;
00630 
00631     basis = args[4]->intValue();
00632   }
00633 
00634   QDate settlement;
00635   QDate maturity;
00636   double investment;
00637   double redemption;
00638 
00639   if ( !getDate( context, args[0], settlement ) )
00640     return false;
00641 
00642   if ( !getDate( context, args[1], maturity ) )
00643     return false;
00644 
00645   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00646     return false;
00647 
00648   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00649     return false;
00650 
00651   investment = args[2]->doubleValue();
00652   redemption = args[3]->doubleValue();
00653 
00654   double d = daysBetweenDates( settlement, maturity, basis );
00655   double y = daysPerYear( settlement, basis );
00656 
00657   if ( d <= 0 || y <= 0 || investment == 0 || basis < 0 || basis > 4 )
00658     return false;
00659 
00660   double result = ( redemption -investment ) / investment * ( y / d );
00661 
00662   context.setValue( new KSValue( result ) );
00663   return true;
00664 }
00665 
00666 
00667 // Function: DURATION
00668 bool kspreadfunc_duration( KSContext& context )
00669 {
00670   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00671 
00672   if ( !KSUtil::checkArgumentsCount( context, 3, "DURATION", true ) )
00673     return false;
00674 
00675   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00676     return false;
00677   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
00678     return false;
00679   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00680     return false;
00681 
00682   double rate = args[0]->doubleValue();
00683   double pv   = args[1]->doubleValue();
00684   double fv   = args[2]->doubleValue();
00685 
00686   if ( rate <= 0.0 )
00687     return false;
00688   if ( fv == 0.0 || pv == 0.0 )
00689     return false;
00690   if ( fv / pv < 0 )
00691     return false;
00692 
00693   context.setValue( new KSValue( log( fv / pv ) / log( 1.0 + rate ) ) );
00694   return true;
00695 }
00696 
00697 // Function: PMT
00698 bool kspreadfunc_pmt( KSContext& context )
00699 {
00700   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00701 
00702   int type = -1;
00703   double fv = -1.0;
00704 
00705   if ( !KSUtil::checkArgumentsCount( context, 5, "PMT", false ) )
00706   {
00707     type = 0;
00708 
00709     if ( !KSUtil::checkArgumentsCount( context, 4, "PMT", false ) )
00710     {
00711       fv = 0.0;
00712 
00713       if ( !KSUtil::checkArgumentsCount( context, 3, "PMT", true ) )
00714         return false;
00715     }
00716   }
00717 
00718   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00719     return false;
00720   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
00721     return false;
00722   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00723     return false;
00724   if ( fv == -1.0 )
00725   {
00726     if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00727       return false;
00728     fv = args[3]->doubleValue();
00729   }
00730   if ( type == -1 )
00731   {
00732     if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
00733       return false;
00734     type = args[4]->intValue();
00735   }
00736 
00737   double rate = args[0]->doubleValue();
00738   double nper = args[1]->doubleValue();
00739   double pv   = args[2]->doubleValue();
00740 
00741   context.setValue( new KSValue( getPay( rate, nper, pv, fv, type ) ) );
00742   return true;
00743 }
00744 
00745 // Function: NPER
00746 bool kspreadfunc_nper( KSContext& context )
00747 {
00748   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00749 
00750   double fv = 0.0;
00751   int type  = 0;
00752 
00753   if ( KSUtil::checkArgumentsCount( context, 5, "NPER", true ) )
00754   {
00755     if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
00756       return false;
00757     if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00758       return false;
00759 
00760     fv   = args[3]->doubleValue();
00761     type = args[4]->intValue();
00762   }
00763   else
00764   if ( KSUtil::checkArgumentsCount( context, 4, "NPER", true ) )
00765   {
00766     type = 0;
00767     if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00768       return false;
00769 
00770     fv   = args[3]->doubleValue();
00771   }
00772   else
00773   if ( !KSUtil::checkArgumentsCount( context, 3, "NPER", false ) )
00774     return false;
00775 
00776   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00777     return false;
00778   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
00779     return false;
00780   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00781     return false;
00782 
00783   double rate = args[0]->doubleValue();
00784   double pmt  = args[1]->doubleValue();
00785   double pv   = args[2]->doubleValue();
00786 
00787   if ( rate <= 0.0 )
00788     return false;
00789 
00790   // taken from Gnumeric
00791   double d  = ( pmt * ( 1.0 + rate * type ) - fv * rate );
00792   double d2 = pv * rate + pmt * ( 1.0 + rate * type );
00793 
00794   double res = d / d2;
00795 
00796   if ( res <= 0.0 )
00797     return false;
00798 
00799   context.setValue( new KSValue( log( res ) / log( 1.0 + rate ) ) );
00800   return true;
00801 }
00802 
00803 // Function: ISPMT
00804 bool kspreadfunc_ispmt( KSContext& context )
00805 {
00806   QValueList<KSValue::Ptr> & args = context.value()->listValue();
00807 
00808   if ( !KSUtil::checkArgumentsCount( context, 4, "ISPMT", false ) )
00809     return false;
00810 
00811   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00812     return false;
00813   if ( !KSUtil::checkType( context, args[1], KSValue::IntType, true ) )
00814     return false;
00815   if ( !KSUtil::checkType( context, args[2], KSValue::IntType, true ) )
00816     return false;
00817   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00818     return false;
00819 
00820   double rate = args[0]->doubleValue();
00821   int    per  = args[1]->intValue();
00822   int    nper = args[2]->intValue();
00823   double pv   = args[3]->doubleValue();
00824 
00825   if ( per < 1 || per > nper )
00826     return false;
00827 
00828   double d = -pv * rate;
00829 
00830   context.setValue( new KSValue( d - ( d / nper * per ) ) );
00831   return true;
00832 }
00833 
00834 // Function: IPMT
00835 bool kspreadfunc_ipmt( KSContext& context )
00836 {
00837   QValueList<KSValue::Ptr>& args = context.value()->listValue();
00838 
00839   double rate;
00840   double per;
00841   double nper;
00842   double pv;
00843   double fv = 0.0;
00844   int type  = 0;
00845 
00846   if ( KSUtil::checkArgumentsCount( context, 6, "IPMT", true ) )
00847   {
00848     if ( !KSUtil::checkType( context, args[5], KSValue::IntType, true ) )
00849       return false;
00850     if ( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
00851       return false;
00852     type = args[5]->intValue();
00853     fv   = args[4]->doubleValue();
00854   }
00855   else
00856   if ( KSUtil::checkArgumentsCount( context, 5, "IPMT", true ) )
00857   {
00858     if ( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
00859       return false;
00860 
00861     fv = args[4]->doubleValue();
00862   }
00863   else
00864   if ( !KSUtil::checkArgumentsCount( context, 4, "IPMT", false ) )
00865     return false;
00866 
00867 
00868   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00869     return false;
00870   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
00871     return false;
00872   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00873     return false;
00874   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00875     return false;
00876 
00877   rate = args[0]->doubleValue();
00878   per  = args[1]->doubleValue();
00879   nper = args[2]->doubleValue();
00880   pv   = args[3]->doubleValue();
00881 
00882   double payment = getPay( rate, nper, pv, fv, type );
00883   double ipmt    = -getPrinc( pv, payment, rate, per - 1 );
00884 
00885   context.setValue( new KSValue( ipmt * rate ) );
00886   return true;
00887 }
00888 
00889 // Function: FV
00890 /* Returns future value, given current value, interest rate and time */
00891 bool kspreadfunc_fv( KSContext& context )
00892 {
00893   QValueList<KSValue::Ptr>& args = context.value()->listValue();
00894 
00895   if ( !KSUtil::checkArgumentsCount( context, 3, "FV", true ) )
00896     return false;
00897 
00898   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00899     return false;
00900   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
00901     return false;
00902   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00903     return false;
00904 
00905   double present = args[0]->doubleValue();
00906   double interest = args[1]->doubleValue();
00907   double periods = args[2]->doubleValue();
00908 
00909   context.setValue( new KSValue( present * pow(1+interest, periods)));
00910   return true;
00911 }
00912 
00913 // Function: compound
00914 /* Returns value after compounded interest, given principal, rate, periods
00915 per year and year */
00916  bool kspreadfunc_compound( KSContext& context )
00917 {
00918   QValueList<KSValue::Ptr>& args = context.value()->listValue();
00919 
00920   if ( !KSUtil::checkArgumentsCount( context, 4, "compound", true ) )
00921     return false;
00922 
00923   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00924     return false;
00925   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
00926     return false;
00927   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00928     return false;
00929   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
00930     return false;
00931   double principal = args[0]->doubleValue();
00932   double interest = args[1]->doubleValue();
00933   double periods = args[2]->doubleValue();
00934   double years = args[3]->doubleValue();
00935 
00936   context.setValue( new KSValue( principal * pow(1+(interest/periods),
00937 periods*years)));
00938 
00939   return true;
00940 }
00941 
00942 // Function: continuous
00943 /* Returns value after continuous compounding of interest, given prinicpal,
00944 rate and years */
00945 bool kspreadfunc_continuous( KSContext& context )
00946 {
00947     // If you still don't understand this, let me know!  ;-)  jsinger@leeta.net
00948   QValueList<KSValue::Ptr>& args = context.value()->listValue();
00949 
00950   if ( !KSUtil::checkArgumentsCount( context, 3, "continuous", true ) )
00951     return false;
00952 
00953   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00954     return false;
00955   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
00956     return false;
00957   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00958     return false;
00959   double principal = args[0]->doubleValue();
00960   double interest = args[1]->doubleValue();
00961   double years = args[2]->doubleValue();
00962 
00963 
00964   context.setValue( new KSValue( principal * exp(interest * years)));
00965   return true;
00966 }
00967 
00968 // Function: PV
00969 bool kspreadfunc_pv( KSContext& context )
00970 {
00971 /* Returns presnt value, given future value, interest rate and years */
00972   QValueList<KSValue::Ptr>& args = context.value()->listValue();
00973 
00974   if ( !KSUtil::checkArgumentsCount( context, 3, "PV", true ) )
00975     return false;
00976 
00977   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
00978     return false;
00979   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
00980     return false;
00981   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
00982     return false;
00983   double future = args[0]->doubleValue();
00984   double interest = args[1]->doubleValue();
00985   double periods = args[2]->doubleValue();
00986 
00987 
00988   context.setValue( new KSValue( future / pow(1+interest, periods)));
00989   return true;
00990 }
00991 
00992 // Function: PV_annuity
00993 bool kspreadfunc_pv_annuity( KSContext& context )
00994 {
00995     /* Returns present value of an annuity or cash flow, given payment,
00996        interest rate,
00997        periods, initial amount and whether payments are made at the start (TRUE)
00998        or end of a period */
00999 
01000     QValueList<KSValue::Ptr>& args = context.value()->listValue();
01001 
01002     if ( !KSUtil::checkArgumentsCount( context, 3, "PV_annuity", true ) )
01003     return false;
01004 
01005     if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01006     return false;
01007     if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01008     return false;
01009     if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
01010     return false;
01011     double amount = args[0]->doubleValue();
01012     double interest = args[1]->doubleValue();
01013     double periods = args[2]->doubleValue();
01014 
01015     double result;
01016     result = amount * (1 - 1/(pow( (1+interest), periods ))) / interest ;
01017 
01018   context.setValue( new KSValue( result ) );
01019 
01020   return true;
01021 }
01022 
01023 // Function: FV_annnuity
01024 bool kspreadfunc_fv_annuity( KSContext& context )
01025 {
01026     /* Returns future value of an annuity or cash flow, given payment, interest
01027        rate and periods */
01028 
01029     QValueList<KSValue::Ptr>& args = context.value()->listValue();
01030 
01031     if ( !KSUtil::checkArgumentsCount( context, 3, "FV_annuity", true ) )
01032     return false;
01033 
01034     if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01035     return false;
01036     if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01037     return false;
01038     if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
01039     return false;
01040     double amount= args[0]->doubleValue();
01041     double interest = args[1]->doubleValue();
01042     double periods = args[2]->doubleValue();
01043 
01044     double result;
01045 
01046     result = amount * ((pow( (1+interest),periods))/interest - 1/interest)   ;
01047 
01048     context.setValue( new KSValue( result ) );
01049 
01050     return true;
01051 }
01052 
01053 // Function: effective
01054 bool kspreadfunc_effective( KSContext& context )
01055 {
01056 /* Returns effective interest rate given nominal rate and periods per year */
01057 
01058   QValueList<KSValue::Ptr>& args = context.value()->listValue();
01059 
01060   if ( !KSUtil::checkArgumentsCount( context, 2, "effective", true ) )
01061     return false;
01062 
01063   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01064     return false;
01065   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01066     return false;
01067   double nominal = args[0]->doubleValue();
01068   double periods = args[1]->doubleValue();
01069 
01070   context.setValue( new KSValue(  pow( 1 + (nominal/periods), periods )- 1 ) );
01071 
01072   return true;
01073 }
01074 
01075 // Function: zero_coupon
01076 bool kspreadfunc_zero_coupon( KSContext& context )
01077 {
01078 /* Returns effective interest rate given nominal rate and periods per year */
01079 
01080   QValueList<KSValue::Ptr>& args = context.value()->listValue();
01081 
01082   if ( !KSUtil::checkArgumentsCount( context, 3, "zero_coupon", true ) )
01083     return false;
01084 
01085   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01086     return false;
01087   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01088     return false;
01089   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
01090     return false;
01091   double face = args[0]->doubleValue();
01092   double rate = args[1]->doubleValue();
01093   double years = args[2]->doubleValue();
01094 
01095   context.setValue( new KSValue(  face / pow( (1 + rate), years )  ) );
01096 
01097   return true;
01098 }
01099 
01100 // Function: level_coupon
01101 bool kspreadfunc_level_coupon( KSContext& context )
01102 {
01103 /* Returns effective interest rate given nominal rate and periods per year */
01104 
01105   QValueList<KSValue::Ptr>& args = context.value()->listValue();
01106 
01107   if ( !KSUtil::checkArgumentsCount( context, 5, "level_coupon", true ) )
01108     return false;
01109 
01110   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01111     return false;
01112   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01113     return false;
01114   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
01115     return false;
01116   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
01117     return false;
01118   if ( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
01119     return false;
01120   double face = args[0]->doubleValue();
01121   double coupon_rate = args[1]->doubleValue();
01122   double coupon_year = args[2]->doubleValue();
01123   double years = args[3]->doubleValue();
01124   double market_rate = args[4]->doubleValue();
01125 
01126   double coupon = coupon_rate * face / coupon_year;
01127   double interest =  market_rate/coupon_year;
01128   double pv_annuity = (1 - 1/(pow( (1+interest), (years*coupon_year) ))) / interest ;
01129   context.setValue( new KSValue( coupon * pv_annuity + (face/ pow( (1+interest), (years*coupon_year) ) ) ) );
01130 
01131   return true;
01132 }
01133 
01134 // Function: nominal
01135 bool kspreadfunc_nominal( KSContext& context )
01136 {
01137 /* Returns nominal interest rate given effective rate and periods per year */
01138 
01139   QValueList<KSValue::Ptr>& args = context.value()->listValue();
01140 
01141   if ( !KSUtil::checkArgumentsCount( context, 2, "nominal", true ) )
01142     return false;
01143 
01144   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01145     return false;
01146   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01147     return false;
01148   double effective = args[0]->doubleValue();
01149   double periods = args[1]->doubleValue();
01150 
01151   if ( periods == 0.0 ) // Check null
01152       return false;
01153 
01154   context.setValue( new KSValue( periods * (pow( (effective + 1), (1 / periods) ) -1) ) );
01155 
01156   return true;
01157 }
01158 
01159 // Function: SLN
01160 /* straight-line depreciation for a single period */
01161 bool kspreadfunc_sln( KSContext& context )
01162 {
01163   QValueList<KSValue::Ptr>& args = context.value()->listValue();
01164 
01165   if ( !KSUtil::checkArgumentsCount( context, 3, "SLN", true ) )
01166     return false;
01167 
01168   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01169     return false;
01170   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01171     return false;
01172   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
01173     return false;
01174 
01175   double cost = args[0]->doubleValue();
01176   double salvage_value = args[1]->doubleValue();
01177   double life = args[2]->doubleValue();
01178 
01179   // sentinel check
01180   if( life <= 0.0 ) return false;
01181 
01182   context.setValue( new KSValue( (cost - salvage_value) / life ) );
01183 
01184   return true;
01185 }
01186 
01187 // Function: SYD
01188 /* sum-of-years digits depreciation */
01189 bool kspreadfunc_syd( KSContext& context )
01190 {
01191   QValueList<KSValue::Ptr>& args = context.value()->listValue();
01192 
01193   if ( !KSUtil::checkArgumentsCount( context, 4, "SYD", true ) )
01194     return false;
01195 
01196   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01197     return false;
01198   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01199     return false;
01200   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
01201     return false;
01202   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
01203     return false;
01204 
01205   double cost = args[0]->doubleValue();
01206   double salvage_value = args[1]->doubleValue();
01207   double life = args[2]->doubleValue();
01208   double period = args[3]->doubleValue();
01209 
01210   // sentinel check
01211   if( life <= 0.0 ) return false;
01212 
01213   context.setValue( new KSValue( ( ( (cost - salvage_value) * (life - period + 1) * 2) /
01214      (life * (life + 1.0) ) ) ) ) ;
01215 
01216   return true;
01217 }
01218 
01219 // Function: DB
01220 /* fixed-declining depreciation */
01221 bool kspreadfunc_db( KSContext& context )
01222 {
01223   QValueList<KSValue::Ptr>& args = context.value()->listValue();
01224 
01225   double month = 12;
01226 
01227   if( KSUtil::checkArgumentsCount( context, 5, "DB", false ) )
01228   {
01229     if( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
01230       return false;
01231     month = args[4]->doubleValue();
01232   }
01233   else
01234   {
01235     if ( !KSUtil::checkArgumentsCount( context, 4, "DB", true ) )
01236       return false;
01237   }
01238 
01239   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01240     return false;
01241   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01242     return false;
01243   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
01244     return false;
01245   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
01246     return false;
01247 
01248   double cost = args[0]->doubleValue();
01249   double salvage = args[1]->doubleValue();
01250   double life = args[2]->doubleValue();
01251   double period = args[3]->doubleValue();
01252 
01253   // sentinel check
01254   if( cost == 0 || life <= 0.0 ) return false;
01255   if( salvage / cost < 0 ) return false;
01256 
01257   double rate = 1000 * (1 - pow( (salvage/cost), (1/life) ));
01258   rate = floor( rate + 0.5 )  / 1000;
01259 
01260   double total = cost * rate * month / 12;
01261 
01262   if( period == 1 )
01263   {
01264     context.setValue( new KSValue( total ) );
01265     return true;
01266   }
01267 
01268   for( int i = 1; i < life; ++i )
01269     if( i == period-1 )
01270     {
01271       context.setValue( new KSValue( rate * (cost-total) ) );
01272       return true;
01273     }
01274     else total += rate * (cost-total);
01275 
01276   context.setValue( new KSValue( (cost-total) * rate * (12-month)/12 ) );
01277 
01278   return true;
01279 }
01280 
01281 // Function: DDB
01282 /* depreciation per period */
01283 bool kspreadfunc_ddb( KSContext& context )
01284 {
01285   QValueList<KSValue::Ptr>& args = context.value()->listValue();
01286 
01287   double factor = 2;
01288 
01289   if( KSUtil::checkArgumentsCount( context, 5, "DB", false ) )
01290   {
01291     if( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
01292       return false;
01293 
01294     factor = args[4]->doubleValue();
01295   }
01296   else
01297   {
01298     if ( !KSUtil::checkArgumentsCount( context, 4, "DB", true ) )
01299       return false;
01300   }
01301 
01302   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01303     return false;
01304   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01305     return false;
01306   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
01307     return false;
01308   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
01309     return false;
01310 
01311   double cost    = args[0]->doubleValue();
01312   double salvage = args[1]->doubleValue();
01313   double life    = args[2]->doubleValue();
01314   double period  = args[3]->doubleValue();
01315   double total   = 0.0;
01316 
01317   if ( cost < 0.0 || salvage < 0.0 || life <= 0.0 || period < 0.0 || factor < 0.0 )
01318     return false;
01319 
01320   for( int i = 0; i < life; ++i )
01321   {
01322     double periodDep = ( cost - total ) * ( factor / life );
01323     if ( i == period - 1 )
01324     {
01325       context.setValue( new KSValue( periodDep ) );
01326       return true;
01327     }
01328     else
01329     {
01330       total += periodDep;
01331     }
01332   }
01333 
01334   context.setValue( new KSValue( cost - total - salvage ) );
01335 
01336   return true;
01337 }
01338 
01339 bool kspreadfunc_ppmt( KSContext & context )
01340 {
01341   QValueList<KSValue::Ptr>& args = context.value()->listValue();
01342   /*
01343 Docs partly copied from OO.
01344 Syntax
01345 PPMT(Rate;Period;NPER;PV;FV;Type)
01346 
01347 Rate is the periodic interest rate.
01348 Period is the amortizement period. P=1 for the first and P=NPER for the last period.
01349 NPER is the total number of periods during which annuity is paid.
01350 PV is the present value in the sequence of payments.
01351 FV (optional) is the desired (future) value.
01352 Type (optional) defines the due date. F=1 for payment at the beginning of a period and F=0 for payment at the end of a period.
01353   */
01354 
01355   double fv = -1.0;
01356   int type = -1;
01357 
01358   if ( !KSUtil::checkArgumentsCount( context, 6, "PPMT", false ) )
01359   {
01360     type = 0;
01361 
01362     if ( !KSUtil::checkArgumentsCount( context, 5, "PPMT", false ) )
01363     {
01364       fv = 0.0;
01365 
01366       if ( !KSUtil::checkArgumentsCount( context, 4, "PPMT", true ) )
01367         return false;
01368     }
01369   }
01370 
01371   if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
01372     return false;
01373   if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
01374     return false;
01375   if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
01376     return false;
01377   if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
01378     return false;
01379   if ( fv == -1 )
01380   {
01381     if ( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
01382       return false;
01383     fv = args[4]->doubleValue();
01384   }
01385   if ( type == -1 )
01386   {
01387     if ( !KSUtil::checkType( context, args[5], KSValue::IntType, true ) )
01388       return false;
01389     type = args[5]->intValue();
01390   }
01391 
01392   double rate   = args[0]->doubleValue();
01393   double period = args[1]->doubleValue();
01394   double nper   = args[2]->doubleValue();
01395   double pv     = args[3]->doubleValue();
01396 
01397   double pay  = getPay( rate, nper, pv, fv, type );
01398   double ipmt = -getPrinc( pv, pay, rate, period - 1 ) * rate;
01399 
01400   context.setValue( new KSValue( pay - ipmt ) );
01401 
01402   return true;
01403 }
01404 
01405 // Function: EURO
01406 bool kspreadfunc_euro( KSContext& context )
01407 {
01408   QValueList<KSValue::Ptr>& args = context.value()->listValue();
01409 
01410   if ( !KSUtil::checkArgumentsCount( context, 1, "EURO", true ) )
01411     return false;
01412 
01413   if ( !KSUtil::checkType( context, args[0], KSValue::StringType, true ) )
01414     return false;
01415 
01416   QString currency = args[0]->stringValue().upper();
01417   double result = -1;
01418 
01419   if( currency == "ATS" ) result = 13.7603;  // Austria
01420   else if( currency == "BEF" ) result = 40.3399;  // Belgium
01421   else if( currency == "DEM" ) result = 1.95583;  // Germany
01422   else if( currency == "ESP" ) result = 166.386;  // Spain
01423   else if( currency == "FIM" ) result = 5.94573;  // Finland
01424   else if( currency == "FRF" ) result = 6.55957;  // France
01425   else if( currency == "GRD" ) result = 340.75;   // Greece
01426   else if( currency == "IEP" ) result = 0.787564; // Ireland
01427   else if( currency == "ITL" ) result = 1936.27;  // Italy
01428   else if( currency == "LUX" ) result = 40.3399;  // Luxemburg
01429   else if( currency == "NLG" ) result = 2.20371;  // Nederland
01430   else if( currency == "PTE" ) result = 200.482;  // Portugal
01431 
01432   if( result <= 0 ) return false;
01433 
01434   context.setValue( new KSValue( result ) );
01435   return true;
01436 }
KDE Logo
This file is part of the documentation for kspread Library Version 1.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Feb 13 09:43:10 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003