Commit 1b2cb619 authored by Jukka-Pekka Iivonen's avatar Jukka-Pekka Iivonen Committed by jpekka

Removed the last bogus msgid to make it compile again.

1999-08-20  Jukka-Pekka Iivonen  <iivonen@iki.fi>

	* po/de.po: Removed the last bogus msgid to make it compile again.

	* src/sheet.c (sheet_insert_object): Added #if ENABLE_BONOBO to
 	make it compile without BONOBO.

	* src/gnumeric-sheet.c (gnumeric_sheet_drag_data_get): Ditto.

	* src/collect.[ch]: Wrote collect_dates and collect_dates_value.

	* src/fn-financial.c: DB() and XNPV() implemented.  DOLLARDE() and
 	DOLLARFR() fixed.

	* src/fn-date.c, src/func.h: get_serial_date made public.

	* TODO: Killed the four functions above from the todo list.
parent 4380e1f8
1999-08-20 Jukka-Pekka Iivonen <iivonen@iki.fi>
* po/de.po: Removed the last bogus msgid to make it compile again.
* src/sheet.c (sheet_insert_object): Added #if ENABLE_BONOBO to
make it compile without BONOBO.
* src/gnumeric-sheet.c (gnumeric_sheet_drag_data_get): Ditto.
* src/collect.[ch]: Wrote collect_dates and collect_dates_value.
* src/fn-financial.c: DB() and XNPV() implemented. DOLLARDE() and
DOLLARFR() fixed.
* src/fn-date.c, src/func.h: get_serial_date made public.
* TODO: Killed the four functions above from the todo list.
1999-08-19 Miguel de Icaza <miguel@gnu.org>
* src/workbook.c (workbook_container_get_object): Finish
......
1999-08-20 Jukka-Pekka Iivonen <iivonen@iki.fi>
* po/de.po: Removed the last bogus msgid to make it compile again.
* src/sheet.c (sheet_insert_object): Added #if ENABLE_BONOBO to
make it compile without BONOBO.
* src/gnumeric-sheet.c (gnumeric_sheet_drag_data_get): Ditto.
* src/collect.[ch]: Wrote collect_dates and collect_dates_value.
* src/fn-financial.c: DB() and XNPV() implemented. DOLLARDE() and
DOLLARFR() fixed.
* src/fn-date.c, src/func.h: get_serial_date made public.
* TODO: Killed the four functions above from the todo list.
1999-08-19 Miguel de Icaza <miguel@gnu.org>
* src/workbook.c (workbook_container_get_object): Finish
......
......@@ -43,19 +43,19 @@ Gnumeric Spread Sheet task list
* Implement Even More Functions
* AREAS, INDEX, MATCH, GETPIVOTDATA, GROWTH, LOGEST,
PERCENTILE, QUARTILE, and TREND
* Finish LINEST
* AREAS, INDEX, MATCH, GETPIVOTDATA, GROWTH, LOGEST, PERCENTILE,
and QUARTILE
* Finish LINEST and TREND
* ACCRINT, ACCRINTM, AMORDEGRC, AMORLINC, COUPDAYBS, COUPDAYS,
COUPDAYSNC, COUPNCD, COUPNUM, COUPPCD, CUMIPMT, CUMPRINC, DB,
DDB, DISC, FVSCHEDULE, INTRATE, IRR, MDURATION, MIRR, ODDFPRICE,
COUPDAYSNC, COUPNCD, COUPNUM, COUPPCD, CUMIPMT, CUMPRINC, DDB,
DISC, FVSCHEDULE, INTRATE, IRR, MDURATION, MIRR, ODDFPRICE,
ODDFYIELD, ODDLPRICE, ODDLYIELD, PRICE, PRICEDISC, PRICEMAT,
RECEIVED, TBILLEQ, TBILLPRICE, TBILLYIELD, VDB, XIRR, XNPV,
YIELD, YIELDDISC, and YIELDMAT.
RECEIVED, TBILLEQ, TBILLPRICE, TBILLYIELD, VDB, XIRR, YIELD,
YIELDDISC, and YIELDMAT.
* Fix the Following Functions
* CELL, DAVERAGE, DGET, DOLLARDE, DOLLARFR, PERCENTRANK, VLOOKUP
* CELL, DAVERAGE, DGET, PERCENTRANK, VLOOKUP
* Printing
* Save print information in workbook
......
......@@ -14,7 +14,7 @@
#define DAY_SECONDS (3600*24)
static float_t
float_t
get_serial_date (const Value *v)
{
float_t serial;
......
......@@ -13,6 +13,7 @@
#include "utils.h"
#include "func.h"
#include "goal-seek.h"
#include "collect.h"
/*
......@@ -182,8 +183,49 @@ gnumeric_nominal (FunctionEvalInfo *ei, Value **argv)
}
static char *help_db = {
N_("@FUNCTION=DB\n"
"@SYNTAX=DB(r,nper)\n"
"@DESCRIPTION="
"DB returns the "
"\n"
"@SEEALSO=")
};
static Value *
gnumeric_db (FunctionEvalInfo *ei, Value **argv)
{
float_t rate;
float_t cost, salvage, life, period, month;
float_t total;
int i;
cost = value_get_as_float (argv[0]);
salvage = value_get_as_float (argv[1]);
life = value_get_as_float (argv[2]);
period = value_get_as_float (argv[3]);
if (argv[4] == NULL)
month = 12;
else
month = value_get_as_float (argv[4]);
rate = 1 - pow((salvage / cost), (1 / life));
rate *= 1000;
rate = floor(rate+0.5) / 1000;
total = cost * rate * month / 12;
if (period == 1)
return value_new_float (total);
for (i=1; i<life; i++)
if (i == period-1)
return value_new_float ((cost - total) * rate);
else
total += (cost - total) * rate;
return value_new_float (((cost - total) * rate * (12 - month)) / 12);
}
static char *help_sln = {
N_("@FUNCTION=SLN\n"
......@@ -224,13 +266,15 @@ static char *help_syd = {
N_("@FUNCTION=SYD\n"
"@SYNTAX=SYD(cost,salvage_value,life,period)\n"
"@DESCRIPTION=Calculates the sum-of-years digits depriciation for an "
"@DESCRIPTION="
"Calculates the sum-of-years digits depriciation for an "
"asset based on its cost, salvage value, anticipated life and a "
"particular period."
"\n"
"Formula for sum-of-years digits depriciation is:"
"\n"
"Depriciation expense = ( cost - salvage_value ) * (life - period + 1) * 2 / life * (life + 1)"
"Depriciation expense = ( cost - salvage_value ) * (life - period "
"+ 1) * 2 / life * (life + 1)."
"\n"
"\t@cost = cost of an asset when acquired (market value)"
"\t@salvage_value = amount you get when asset sold at the end of life"
......@@ -290,9 +334,9 @@ gnumeric_dollarde (FunctionEvalInfo *ei, Value **argv)
floored = floor (fractional_dollar);
rest = fractional_dollar - floored;
tmp = (int) (rest * pow(10, n));
return value_new_float (floored + ((float_t) tmp / fraction));
return value_new_float (floored + ((float_t) rest * pow(10,n) /
fraction));
}
static char *help_dollarfr = {
......@@ -321,16 +365,16 @@ gnumeric_dollarfr (FunctionEvalInfo *ei, Value **argv)
if (fraction <= 0)
return value_new_error (&ei->pos, gnumeric_err_NUM);
tmp = fraction;
/* Count digits in fraction */
tmp = fraction;
for (n=0; tmp; n++)
tmp /= 10;
floored = floor (fractional_dollar);
rest = fractional_dollar - floored;
tmp = (int) (rest * fraction);
return value_new_float (floored + ((float_t) tmp / pow(10, n)));
return value_new_float (floored + ((float_t) (rest*fraction) /
pow(10, n)));
}
......@@ -403,7 +447,8 @@ gnumeric_rate (FunctionEvalInfo *ei, Value **argv)
return value_new_error (&ei->pos, gnumeric_err_NUM);
else {
/* Exact case. */
return value_new_float (pow (-udata.fv / udata.pv, -1.0 / udata.nper) - 1);
return value_new_float (pow (-udata.fv / udata.pv,
-1.0 / udata.nper) - 1);
}
}
......@@ -412,7 +457,8 @@ gnumeric_rate (FunctionEvalInfo *ei, Value **argv)
else {
/* Root finding case. The following was derived by setting
type==0 and estimating (1+r)^n ~= 1+rn. */
rate0 = -((udata.pmt * udata.nper + udata.fv) / udata.pv + 1) / udata.nper;
rate0 = -((udata.pmt * udata.nper + udata.fv) /
udata.pv + 1) / udata.nper;
}
#if 0
......@@ -459,15 +505,20 @@ gnumeric_pv (FunctionEvalInfo *ei, Value **argv)
pvif = calculate_pvif (rate, nper);
fvifa = calculate_fvifa (rate, nper);
return value_new_float ( ( (-1.0) * fv - pmt * ( 1.0 + rate * type ) * fvifa ) / pvif );
return value_new_float ( ( (-1.0) * fv - pmt *
( 1.0 + rate * type ) * fvifa ) / pvif );
}
static char *help_npv = {
N_("@FUNCTION=NPV\n"
"@SYNTAX=NPV(rate,v1,v2,...)\n"
"@DESCRIPTION=Calculates the net present value of an investment."
"@DESCRIPTION="
"NPV calculates the net present value of an investment generating "
"peridic payments. @rate is the periodic interest rate and "
"@v1, @v2, ... are the periodic payments. If the schedule of the "
"cash flows are not periodic use the XNPV function. "
"\n"
"@SEEALSO=PV")
"@SEEALSO=PV,XNPV")
};
typedef struct {
......@@ -507,6 +558,58 @@ gnumeric_npv (FunctionEvalInfo *ei, GList *nodes)
return (v != NULL) ? v : value_new_float (p.sum);
}
static char *help_xnpv = {
N_("@FUNCTION=XNPV\n"
"@SYNTAX=XNPV(rate,values,dates)\n"
"@DESCRIPTION="
"XNPV calculates the net present value of an investment. The "
"schedule of the cash flows is given in @dates array. The first "
"date indicates the beginning of the payment schedule. @rate "
"is the interest rate and @values are the payments. "
"\n"
"If @values and @dates contain unequal number of values, XNPV "
"returns the #NUM error. "
"\n"
"@SEEALSO=NPV,PV")
};
static Value *
gnumeric_xnpv (FunctionEvalInfo *ei, Value **argv)
{
float_t rate, *payments = NULL, *dates = NULL;
float_t sum;
int p_n, d_n, i;
Value *result = NULL;
rate = value_get_as_float (argv[0]);
sum = 0;
payments = collect_floats_value (argv[1], &ei->pos,
COLLECT_IGNORE_STRINGS |
COLLECT_IGNORE_BOOLS,
&p_n, &result);
if (result)
goto out;
dates = collect_dates_value (argv[2], &ei->pos, 0,
&d_n, &result);
if (result)
goto out;
if (p_n != d_n)
return value_new_error (&ei->pos, gnumeric_err_NUM);
for (i=0; i<p_n; i++)
sum += payments[i] / pow(1+rate, (dates[i]-dates[0])/365.0);
result = value_new_float (sum);
out:
g_free (payments);
g_free (dates);
return result;
}
static char *help_fv = {
N_("@FUNCTION=FV\n"
......@@ -713,6 +816,9 @@ void finance_functions_init()
{
FunctionCategory *cat = function_get_category (_("Financial"));
function_add_args (cat, "db", "ffff|f",
"cost,salvage,life,period[,month]",
&help_db, gnumeric_db);
function_add_args (cat, "dollarde", "ff",
"fractional_dollar,fraction",
&help_dollarde, gnumeric_dollarde);
......@@ -747,4 +853,6 @@ void finance_functions_init()
function_add_args (cat, "syd", "ffff",
"cost,salvagevalue,life,period",
&help_syd, gnumeric_syd);
function_add_args (cat, "xnpv", "fAA", "rate,values,dates",
&help_xnpv, gnumeric_xnpv);
}
......@@ -3048,8 +3048,3 @@ msgid ""
"@SEEALSO="
msgstr ""
#: src/fn-lookup.c:554
msgid ""
"@FUNCTION=COLUMN\n"
"@SYNTAX=COLUMN([reference])\n"
"@DESCRIPTION=The COLUMN fun
\ No newline at end of file
/*
* collect.c: Helpers to collect ranges of data.
*
* Author:
* Authors:
* Morten Welinder <terra@diku.dk>
* Jukka-Pekka Iivonen <iivonen@iki.fi>
*/
#include "collect.h"
......@@ -147,6 +148,128 @@ collect_floats_value (const Value *val, const EvalPosition *ep,
/* ------------------------------------------------------------------------- */
static Value *
callback_function_dates_collect (const EvalPosition *ep,
Value *value, void *closure)
{
float_t x;
collect_floats_t *cl = (collect_floats_t *)closure;
switch (value->type) {
case VALUE_EMPTY:
return NULL;
case VALUE_BOOLEAN:
if (cl->flags & COLLECT_IGNORE_BOOLS)
return NULL;
else
return value_new_error (ep, gnumeric_err_VALUE);
break;
case VALUE_ERROR:
if (cl->flags & COLLECT_IGNORE_ERRORS)
return NULL;
else
return value_new_error (ep, gnumeric_err_VALUE);
break;
case VALUE_INTEGER:
case VALUE_FLOAT:
x = value_get_as_float (value);
break;
case VALUE_STRING:
x = get_serial_date (value);
break;
default:
g_warning ("Trouble in callback_function_dates_collect. (%d)",
value->type);
return NULL;
}
if (cl->count == cl->alloc_count) {
cl->alloc_count *= 2;
cl->data = g_realloc (cl->data, cl->alloc_count *
sizeof (float_t));
}
cl->data[cl->count++] = x;
return NULL;
}
/* ------------------------------------------------------------------------- */
/*
* collect_dates:
*
* exprlist: List of expressions to evaluate.
* cr: Current location (for resolving relative cells).
* flags: COLLECT_IGNORE_BOOLS: silently ignore bools.
* COLLECT_ZEROONE_BOOLS: count FALSE as 0, TRUE as 1.
* (Alternative: return #VALUE!.)
* n: Output parameter for number of floats.
*
* Return value:
* NULL in case of strict and a blank.
* A copy of the error in the case of strict and an error.
* Non-NULL in case of success. Then n will be set.
*
* Evaluate a list of expressions and return the result as an array of
* float_t.
*/
static float_t *
collect_dates (GList *exprlist, const EvalPosition *ep, CollectFlags flags,
int *n, Value **error)
{
Value * err;
collect_floats_t cl;
cl.alloc_count = 20;
cl.data = g_new (float_t, cl.alloc_count);
cl.count = 0;
cl.flags = flags;
err = function_iterate_argument_values(ep,
&callback_function_dates_collect,
&cl, exprlist, TRUE);
if (err) {
g_assert (err->type == VALUE_ERROR);
g_free (cl.data);
/* Be careful not to make value_terminate into a real value */
*error = (err != value_terminate())? value_duplicate(err) : err;
return NULL;
}
*n = cl.count;
return cl.data;
}
/* ------------------------------------------------------------------------- */
/* Like collect_dates, but takes a value instead of an expression list.
Presumably most useful when the value is an array. */
float_t *
collect_dates_value (const Value *val, const EvalPosition *ep,
CollectFlags flags, int *n, Value **error)
{
GList *exprlist;
ExprTree *expr_val;
float_t *res;
expr_val = expr_tree_new_constant (value_duplicate (val));
exprlist = g_list_prepend (NULL, expr_val);
res = collect_dates (exprlist, ep, flags, n, error);
expr_tree_unref (expr_val);
g_list_free (exprlist);
return res;
}
/* ------------------------------------------------------------------------- */
Value *
float_range_function (GList *exprlist, FunctionEvalInfo *ei,
float_range_function_t func,
......
......@@ -23,6 +23,10 @@ float_t *collect_floats_value (const Value *val, const EvalPosition *ep,
CollectFlags flags,
int *n, Value **error);
float_t *collect_dates_value (const Value *val, const EvalPosition *ep,
CollectFlags flags,
int *n, Value **error);
Value *float_range_function (GList *exprlist, FunctionEvalInfo *ei,
float_range_function_t func,
CollectFlags flags,
......
......@@ -14,7 +14,7 @@
#define DAY_SECONDS (3600*24)
static float_t
float_t
get_serial_date (const Value *v)
{
float_t serial;
......
......@@ -13,6 +13,7 @@
#include "utils.h"
#include "func.h"
#include "goal-seek.h"
#include "collect.h"
/*
......@@ -182,8 +183,49 @@ gnumeric_nominal (FunctionEvalInfo *ei, Value **argv)
}
static char *help_db = {
N_("@FUNCTION=DB\n"
"@SYNTAX=DB(r,nper)\n"
"@DESCRIPTION="
"DB returns the "
"\n"
"@SEEALSO=")
};
static Value *
gnumeric_db (FunctionEvalInfo *ei, Value **argv)
{
float_t rate;
float_t cost, salvage, life, period, month;
float_t total;
int i;
cost = value_get_as_float (argv[0]);
salvage = value_get_as_float (argv[1]);
life = value_get_as_float (argv[2]);
period = value_get_as_float (argv[3]);
if (argv[4] == NULL)
month = 12;
else
month = value_get_as_float (argv[4]);
rate = 1 - pow((salvage / cost), (1 / life));
rate *= 1000;
rate = floor(rate+0.5) / 1000;
total = cost * rate * month / 12;
if (period == 1)
return value_new_float (total);
for (i=1; i<life; i++)
if (i == period-1)
return value_new_float ((cost - total) * rate);
else
total += (cost - total) * rate;
return value_new_float (((cost - total) * rate * (12 - month)) / 12);
}
static char *help_sln = {
N_("@FUNCTION=SLN\n"
......@@ -224,13 +266,15 @@ static char *help_syd = {
N_("@FUNCTION=SYD\n"
"@SYNTAX=SYD(cost,salvage_value,life,period)\n"
"@DESCRIPTION=Calculates the sum-of-years digits depriciation for an "
"@DESCRIPTION="
"Calculates the sum-of-years digits depriciation for an "
"asset based on its cost, salvage value, anticipated life and a "
"particular period."
"\n"
"Formula for sum-of-years digits depriciation is:"
"\n"
"Depriciation expense = ( cost - salvage_value ) * (life - period + 1) * 2 / life * (life + 1)"
"Depriciation expense = ( cost - salvage_value ) * (life - period "
"+ 1) * 2 / life * (life + 1)."
"\n"
"\t@cost = cost of an asset when acquired (market value)"
"\t@salvage_value = amount you get when asset sold at the end of life"
......@@ -290,9 +334,9 @@ gnumeric_dollarde (FunctionEvalInfo *ei, Value **argv)
floored = floor (fractional_dollar);
rest = fractional_dollar - floored;
tmp = (int) (rest * pow(10, n));
return value_new_float (floored + ((float_t) tmp / fraction));
return value_new_float (floored + ((float_t) rest * pow(10,n) /
fraction));
}
static char *help_dollarfr = {
......@@ -321,16 +365,16 @@ gnumeric_dollarfr (FunctionEvalInfo *ei, Value **argv)
if (fraction <= 0)
return value_new_error (&ei->pos, gnumeric_err_NUM);
tmp = fraction;
/* Count digits in fraction */
tmp = fraction;
for (n=0; tmp; n++)
tmp /= 10;
floored = floor (fractional_dollar);
rest = fractional_dollar - floored;
tmp = (int) (rest * fraction);
return value_new_float (floored + ((float_t) tmp / pow(10, n)));
return value_new_float (floored + ((float_t) (rest*fraction) /
pow(10, n)));
}
......@@ -403,7 +447,8 @@ gnumeric_rate (FunctionEvalInfo *ei, Value **argv)
return value_new_error (&ei->pos, gnumeric_err_NUM);
else {
/* Exact case. */
return value_new_float (pow (-udata.fv / udata.pv, -1.0 / udata.nper) - 1);
return value_new_float (pow (-udata.fv / udata.pv,
-1.0 / udata.nper) - 1);
}
}
......@@ -412,7 +457,8 @@ gnumeric_rate (FunctionEvalInfo *ei, Value **argv)
else {
/* Root finding case. The following was derived by setting
type==0 and estimating (1+r)^n ~= 1+rn. */
rate0 = -((udata.pmt * udata.nper + udata.fv) / udata.pv + 1) / udata.nper;
rate0 = -((udata.pmt * udata.nper + udata.fv) /
udata.pv + 1) / udata.nper;
}
#if 0
......@@ -459,15 +505,20 @@ gnumeric_pv (FunctionEvalInfo *ei, Value **argv)
pvif = calculate_pvif (rate, nper);
fvifa = calculate_fvifa (rate, nper);
return value_new_float ( ( (-1.0) * fv - pmt * ( 1.0 + rate * type ) * fvifa ) / pvif );
return value_new_float ( ( (-1.0) * fv - pmt *
( 1.0 + rate * type ) * fvifa ) / pvif );
}
static char *help_npv = {
N_("@FUNCTION=NPV\n"
"@SYNTAX=NPV(rate,v1,v2,...)\n"
"@DESCRIPTION=Calculates the net present value of an investment."
"@DESCRIPTION="
"NPV calculates the net present value of an investment generating "
"peridic payments. @rate is the periodic interest rate and "
"@v1, @v2, ... are the periodic payments. If the schedule of the "
"cash flows are not periodic use the XNPV function. "
"\n"
"@SEEALSO=PV")
"@SEEALSO=PV,XNPV")
};
typedef struct {
......@@ -507,6 +558,58 @@ gnumeric_npv (FunctionEvalInfo *ei, GList *nodes)
return (v != NULL) ? v : value_new_float (p.sum);
}
static char *help_xnpv = {
N_("@FUNCTION=XNPV\n"
"@SYNTAX=XNPV(rate,values,dates)\n"
"@DESCRIPTION="
"XNPV calculates the net present value of an investment. The "
"schedule of the cash flows is given in @dates array. The first "
"date indicates the beginning of the payment schedule. @rate "
"is the interest rate and @values are the payments. "
"\n"
"If @values and @dates contain unequal number of values, XNPV "
"returns the #NUM error. "
"\n"
"@SEEALSO=NPV,PV")
};
static Value *
gnumeric_xnpv (FunctionEvalInfo *ei, Value **argv)
{
float_t rate, *payments = NULL, *dates = NULL;
float_t sum;
int p_n, d_n, i;
Value *result = NULL;
rate = value_get_as_float (argv[0]);
sum = 0;