mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Clean out unused financial calculation stand-alone programs
No-one even knew about them! git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@22846 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
2fd588dd32
commit
9b02886804
@ -1,49 +0,0 @@
|
||||
# qtgrep makefile
|
||||
# created by Terry Boldt 3-16-2000
|
||||
#
|
||||
|
||||
GLIB_CFLAGS = `glib-config --cflags`
|
||||
CFLAGS = -O3 $(GLIB_CFLAGS)
|
||||
#CFLAGS = -g
|
||||
|
||||
CC = gcc
|
||||
|
||||
all: financial fini
|
||||
|
||||
HDRS = finproto.h \
|
||||
fin_static_proto.h\
|
||||
fin_spl_protos.h\
|
||||
finvar.h
|
||||
|
||||
OBJSM = fin.o\
|
||||
amort_prt.o\
|
||||
fin-main.o
|
||||
|
||||
OBJSI = fin.o \
|
||||
expression_parser.o\
|
||||
numeric_ops.o\
|
||||
amort_prt.o\
|
||||
amort_opt.o\
|
||||
fin-interactive.o
|
||||
|
||||
financial: $(OBJSM)
|
||||
@echo "linking"
|
||||
$(CC) `glib-config --libs` -o $@ $(OBJSM)
|
||||
|
||||
fini: $(OBJSI)
|
||||
@echo "linking"
|
||||
$(CC) `glib-config --libs` -o $@ $(OBJSI)
|
||||
|
||||
fin.o: fin.c $(HDRS)
|
||||
|
||||
expression_parser.o: expression_parser.c $(HDRS)
|
||||
|
||||
fin-interactive.o: fin-interactive.c $(HDRS)
|
||||
|
||||
fin-main.o: fin-main.c $(HDRS)
|
||||
|
||||
numeric_ops.o: numeric_ops.c $(HDRS)
|
||||
|
||||
amort_prt.o: amort_prt.c $(HDRS)
|
||||
|
||||
amort_opt.o: amort_opt.c $(HDRS)
|
@ -1,989 +0,0 @@
|
||||
Dave - the attached file contains the following files:
|
||||
|
||||
drwx------ 4096 Jul 4 16:20 ./
|
||||
drwxr-xr-x 4096 Jun 19 17:20 ../
|
||||
-rw-r--r-- 211 Jun 23 20:24 .kdbgrc.financial #kdebug file
|
||||
-rw-r--r-- 259 Jul 4 15:24 .kdbgrc.fini #kdebug file
|
||||
-rw-r--r-- 732 Jul 4 15:24 Makefile
|
||||
-rw-r--r-- 5711 Jul 3 20:02 amort_opt.c # display/set amortization options
|
||||
-rw-r--r-- 4392 Jul 4 15:25 amort_opt.o
|
||||
-rw-r--r-- 13020 Jul 4 16:16 amort_prt.c # print amortization schedule(s)
|
||||
-rw-r--r-- 7256 Jul 4 16:16 amort_prt.o
|
||||
-rw-r--r-- 14778 Jul 3 20:09 expression_parser.c # expression parser/evaluator
|
||||
-rw-r--r-- 5148 Jul 4 15:24 expression_parser.o
|
||||
-rw-r--r-- 19225 Jul 3 20:03 fin-interactive.c # demo
|
||||
-rw-r--r-- 12964 Jul 4 15:25 fin-interactive.o
|
||||
-rw-r--r-- 6102 Jul 4 16:01 fin-main.c # fixed examples
|
||||
-rw-r--r-- 5008 Jul 4 16:02 fin-main.o
|
||||
-rwxr-xr-x 1431 Jul 2 19:21 fin-proto.sh* # shell script for making 'h' files
|
||||
-rw-r--r-- 83854 Jul 4 16:34 fin.c # financial and amortization functions
|
||||
-rw-r--r-- 23880 Jul 4 16:16 fin.o
|
||||
-rw-r--r-- 1063 Jun 28 16:28 fin_spl_protos.h # function prototypes
|
||||
-rw-r--r-- 4631 Jul 3 20:07 fin_static_proto.h # function prototypes
|
||||
-rwxr-xr-x 41011 Jul 4 16:16 financial* # executable demo - from fin-main.c
|
||||
-rwxr-xr-x 54720 Jul 4 16:16 fini* # executable demo - from fin-interactive.c
|
||||
-rw-r--r-- 90 Jun 22 20:37 fini-input
|
||||
-rw-r--r-- 2624 Jun 22 20:24 fini-output
|
||||
-rw-r--r-- 7407 Jul 3 20:07 finproto.h # function prototypes
|
||||
-rw-r--r-- 8152 Jul 4 15:23 finvar.h # define global structures used
|
||||
drwx------ 4096 Jun 27 20:24 html/ # html documentation
|
||||
-rw-r--r-- 6938 Jul 3 20:04 numeric_ops.c # numeric functions - for expression parser
|
||||
-rw-r--r-- 2204 Jul 4 15:24 numeric_ops.o
|
||||
-rw-r--r-- 11814 Jun 20 19:58 readme # this file
|
||||
-rw-r--r-- 131016 Jul 4 16:20 sample # output of financial executable
|
||||
|
||||
financial-equations/html:
|
||||
total 164
|
||||
drwx------ 4096 Jun 27 20:24 ./
|
||||
drwx------ 4096 Jul 4 16:20 ../
|
||||
-rw-r--r-- 17430 Jun 20 15:29 amorta.html # amortization schedule
|
||||
-rw-r--r-- 26222 Jun 20 15:29 amortp.html # amortization schedule
|
||||
-rw-r--r-- 2361 Jun 27 20:38 constderv.html # equations derivation
|
||||
-rw-r--r-- 11290 Jun 27 20:25 finderv.html # equations derivation
|
||||
-rw-r--r-- 82204 Jun 27 20:36 finutil.html # basic use of financial calculator
|
||||
|
||||
This 'readme' file is probably somewhat rambling - it is coming off
|
||||
the top of my head with very little organization. Note also that much
|
||||
of the following "explanation" has been duplicated as comments at the
|
||||
top of the "fin.c" and the "expression-parser.c" files. Thus, anyone
|
||||
desiring to use the functions contained therein will have some ready
|
||||
documentation.
|
||||
|
||||
Look into the 'sample' file. It contains sample output from the
|
||||
routines - both from the calculator and the amortization routines. The
|
||||
sample file was created with the "financial" executable. If running
|
||||
Linux, you should be able to execute this program without compiling to
|
||||
recreate 'sample' as "./financial >sample"
|
||||
|
||||
You may want to view the file "finutil.html" in a browser - it
|
||||
explains in detail the calculator functions and variables and concepts
|
||||
and amortization schedule options.
|
||||
|
||||
The file 'finvar.h' contains the structures needed by functions
|
||||
calling the financial functions and amortization functions and the
|
||||
expression parser/evaluator and should be included by any file calling
|
||||
any financial function and and the amortization functions. The two
|
||||
prototype files:
|
||||
|
||||
finproto.h
|
||||
fin_spl_protos.h
|
||||
|
||||
should be "included" by any files containing functions which call
|
||||
either the financial calculator functions (including the amortization
|
||||
functions) or the expression parser/evaluator.
|
||||
|
||||
There are no "global variables". My first iteration on "porting"
|
||||
the calculator contained global variables for the basic financial
|
||||
variables. I decided against doing this for reasons of conflict with
|
||||
other variables used in other modules and also to insure that ANY
|
||||
module in gnucash could call the financial functions and have their
|
||||
own set of financial variables. Thus any gnucash module may use the
|
||||
financial functions without concern of interaction with any other
|
||||
module also using the functions concurrently.
|
||||
|
||||
There are 9 "financial variables". Of the nine, four are ALWAYS set by
|
||||
the "user", i.e., calling function. Of the remaining five, four are
|
||||
set and the fifth computed by the appropriate financial calculator
|
||||
function listed below. The 9 "financial variables" are: (if more than
|
||||
one name is used for a particular financial variable, all are listed)
|
||||
|
||||
n or npp == number of payment periods in the transaction under
|
||||
consideration
|
||||
|
||||
i, nint or ir == nominal interest rate for the transaction.
|
||||
Use the interest rate as used by humans,
|
||||
i.e., 9.5, 8.25, etc. and not 0.095, 0.0825
|
||||
|
||||
pv == present value, i.e., the value of the transaction at the
|
||||
present moment in time. This would be the amount of the
|
||||
loan/mortgage/Certificate of Deposit/bank account/etc.
|
||||
|
||||
pmt == periodic payment
|
||||
|
||||
fv == future value, i.e., the value of the transaction at some
|
||||
future time after n payment periods.
|
||||
|
||||
Of the five values above, four are set by the "user" and the fifth
|
||||
computed. The remaining financial variables are:
|
||||
|
||||
CF == Compounding Frequency, number of compounding periods in one year
|
||||
PF == Payment Frequency, number of payment periods in one year
|
||||
disc == TRUE, 1, for discrete compounding (used by most financial
|
||||
institutions in US)
|
||||
FALSE, 0, for continuous compounding (used by some banks
|
||||
in my area for CDs)
|
||||
bep == TRUE for beginning of periods payments
|
||||
FALSE for end of period payments (the norm in the US at least)
|
||||
|
||||
The function 'set_default(fi_ptr fi)' will set the variables in the
|
||||
'fi' structure to the default values:
|
||||
|
||||
n == 0
|
||||
i = 0.0
|
||||
pv = 0.0
|
||||
pmt = 0.0
|
||||
fv = 0.0
|
||||
CF = 12
|
||||
PF = 12
|
||||
disc = 1
|
||||
bep = 0
|
||||
|
||||
(Maybe this could/should be made locale specific or configurable ??? )
|
||||
|
||||
In addition, there is one other "financial variable" which is not
|
||||
really a financial variable, but which should be specific to any
|
||||
particular financial computation and under the control of the user:
|
||||
|
||||
prec == numeric precesion used for round-off of numeric values, i.e.,
|
||||
number of digits past the radix point.
|
||||
|
||||
I currently have a static function defined in the "fin.c" file:
|
||||
|
||||
static double rnd(
|
||||
double x,
|
||||
unsigned places)
|
||||
{
|
||||
double r;
|
||||
unsigned char buf[50]; /* make buffer large enough */
|
||||
|
||||
if ( places >= 0 ) {
|
||||
sprintf(buf,"%.*f",places,x);
|
||||
sscanf(buf,"%lf",&r);
|
||||
} else r = x;
|
||||
|
||||
return r;
|
||||
} /* rnd */
|
||||
|
||||
The function returns x rounded to the specified number of decimal
|
||||
digits past the radix point. I assume that gnucash currently has such
|
||||
a function. I will need the name of this function, since it is used
|
||||
extensively in the financial computation and the computation of
|
||||
amortization schedules. The function 'rnd' that I have included is
|
||||
pretty simple - it simply writes the double value to a string using
|
||||
'sprintf' to print the value and round the value. It then uses
|
||||
'sscanf' to read the value into a temporary double variable and
|
||||
returns that value. I have written many rounding functions in the past
|
||||
and could never find one that everybody agreed with. Not every one
|
||||
agrees with the rounding rules used by the C 'printf' functions, but
|
||||
at least everybody writing C and C++ uses them and is used to them.
|
||||
|
||||
The financial functions use a structure (defined in 'finvar.h'):
|
||||
|
||||
/* structure used by financial computation routines to store
|
||||
* financial variables */
|
||||
typedef struct financial_info *fi_ptr;
|
||||
typedef struct financial_info {
|
||||
double ir; /* interest rate */
|
||||
double pv; /* present value */
|
||||
double pmt; /* periodic payment */
|
||||
double fv; /* future value */
|
||||
|
||||
unsigned npp; /* number of payment periods */
|
||||
unsigned CF; /* Compounding frequency */
|
||||
unsigned PF; /* payment frequency */
|
||||
unsigned bep; /* beginning/end of period payment flag */
|
||||
/* TRUE == beginning of period */
|
||||
/* FALSE == end of period */
|
||||
unsigned disc; /* discrete/continuous compounding flag */
|
||||
/* TRUE == discrete compounding */
|
||||
/* FALSE == continuous compounding */
|
||||
|
||||
/* precision of roundoff for pv, pmt and fv.
|
||||
* i, Interest not rounded
|
||||
* n, number of periods rounded to integer value,
|
||||
* implicit value of zero, 0
|
||||
*
|
||||
* 2 for US Dollars
|
||||
*/
|
||||
unsigned prec;
|
||||
} financial_info;
|
||||
|
||||
to contain all information used in the financial calculations. The
|
||||
structure is created by the calling function and the variables set by
|
||||
the calling function. The appropriate financial function is called to
|
||||
compute the desired quantity with a pointer to the structure.
|
||||
|
||||
|
||||
The following functions are contained in the financial calculator:
|
||||
|
||||
unsigned N(fi_ptr fi) -- solves for number of payment periods rounded to an
|
||||
integer value. Sets the variable 'npp' in the passed
|
||||
structure and returns the same value.
|
||||
|
||||
double I(fi_ptr fi) -- solves for the nominal interest rate rounded to
|
||||
the precision specified in the structure passed.
|
||||
Sets the variable 'ir' in the passed structure
|
||||
and returns the same value.
|
||||
|
||||
double PV(fi_ptr fi) -- solves for the present value rounded to the precision
|
||||
specified. Sets the variable 'pv' in the passed
|
||||
structure and returns the same value.
|
||||
|
||||
double PMT(fi_ptr fi) -- solves for the periodic payment rounded to the
|
||||
precision specified. Sets the variable 'pmt' in
|
||||
the passed structure and returns the same value.
|
||||
|
||||
double FV(fi_ptr fi) -- solves for the future value rounded to the precision
|
||||
specified. Sets the variable 'fv' in the passed
|
||||
structure and returns the same value.
|
||||
|
||||
The above functions use the following functions for the calculation
|
||||
and round the answer as indicated. The above functions are the
|
||||
"normal" functions called to calculate the corresponding values. I
|
||||
left the following functions as "global" in case there is a need for
|
||||
unrounded, full floating point accuracy answers. They could be
|
||||
converted to "static" functions if there is any conflict or the full
|
||||
accuracy is not needed elsewhere in gnucash. Also these function do
|
||||
not use the financial calculator structure, but rather the variables
|
||||
must be passed as arguments with the desired value returned.
|
||||
|
||||
double _N(ir,pv,pmt,fv,CF,PF,disc,bep) - compute number of payment periods
|
||||
and return value
|
||||
|
||||
double _I(npp,pv,pmt,fv,CF,PF,disc,bep) - compute nominal interest rate and
|
||||
return value
|
||||
|
||||
double _PV(npp,ir,pmt,fv,CF,PF,disc,bep) - compute present value and return
|
||||
value
|
||||
|
||||
double _PMT(npp,ir,pv,fv,CF,PF,disc,bep) - compute periodic payment and
|
||||
return value
|
||||
|
||||
double _FV(npp,ir,pv,pmt,CF,PF,disc,bep) - compute future value and return
|
||||
value
|
||||
|
||||
Note, the return value of '_N' should always be rounded (or truncated,
|
||||
probably rounded) since a fractional payment period is a practical
|
||||
impossibility.
|
||||
|
||||
The financial calculator functions do no "value checking". That is,
|
||||
there is no checking for erroneous values or any "reasonable value
|
||||
testing". The only values that absolutely have to be checked by the
|
||||
calling functions are:
|
||||
|
||||
1: nominal interest rate when calculating one of the other variables.
|
||||
If this value is zero a "divide by zero" error may occur. If the
|
||||
divide by zero error does not occur, then the value calculated
|
||||
will more than likely be returned as 'nan'. Always check this value
|
||||
for non-zero if it is not the value to be computed. A non-zero value
|
||||
is only common sense also, since a zero interest rate is probably
|
||||
meaningless.
|
||||
|
||||
2: number of payment periods. When calculating the nominal interest rate,
|
||||
if the number of payment periods is zero, again a "divide by zero" error
|
||||
may occur. Always check this value for non-zero if it is not the value to
|
||||
be computed. Again, a zero number of payment periods is meaningless.
|
||||
At least one payment must be made or one party to the transaction is
|
||||
making a free gift to the other party - in which case the calculator
|
||||
is not needed.
|
||||
|
||||
Note: I have violated both of these rules in the two demo executables
|
||||
provided. For the 'financial' executable, such a check is not
|
||||
necessary since all of the examples are set statically and it is known
|
||||
that neither interest or number of periods is zero. For the 'fini'
|
||||
executable, they should be checked, but for demo purposes I didn't
|
||||
think it necessary.
|
||||
|
||||
A good user interface would check that the values of CF, PF, disc and
|
||||
bep are set (at least to the default values) and that at least 4 of
|
||||
the remaining variables have been set and the user asked for the fifth
|
||||
value to be computed. Leaving the value of 'fv' to zero would be the
|
||||
normal in most cases.
|
||||
|
||||
I decided that the financial functions should do no value checking,
|
||||
since they are far enough down the call chain that returning in the
|
||||
case of erroneous values is problamatic and adds excessive structure
|
||||
to otherwise extremely simple functions. Also since the value checking
|
||||
that does need to be accomplished is minimal and should optimally be
|
||||
done as close to the user interface as possible.
|
||||
|
||||
|
||||
My first take on a possible user interface would look something like
|
||||
(or as close as I can get in an ASCII text file):
|
||||
|
||||
NOTE: ==xxxxxxxxx== means a GUI box for displaying/entering a value
|
||||
|
||||
((compute)) means a GUI button with the title "compute"
|
||||
|
||||
<<Monthly>> means a GUI box with dropdown values that the user selects
|
||||
there is a name for such a box in GUI nomenclature,
|
||||
but I forget the name
|
||||
|
||||
|| means a GUI check box button (either on or off).
|
||||
The Title for the button would change to reflect
|
||||
the on/off, TRUE/FALSE value
|
||||
|
||||
|**********| means a single line text box that the user could
|
||||
use to enter a string. This box could be used by
|
||||
the user to enter expressions, with named variables,
|
||||
to be evaluated. This box is probably he same kind
|
||||
of GUI box as I have indicated above with == xxxx==
|
||||
|
||||
Possible Financial Calculator GUI:
|
||||
|-------------------------------------------------------------------------|
|
||||
|
||||
Number of
|
||||
Payment Periods ((Compute))
|
||||
==xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
|
||||
|
||||
Interest Rate ((Compute))
|
||||
==xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
|
||||
|
||||
Present Value ((Compute))
|
||||
==xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
|
||||
|
||||
Periodic Payment ((Compute))
|
||||
==xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
|
||||
|
||||
Future Value ((Compute))
|
||||
==xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
|
||||
|
||||
|
||||
Compounding Payment || End of Period Payments
|
||||
Frequency Frequency
|
||||
<<Monthly>> <<Monthly>> || Discrete Compounding
|
||||
|
||||
Expression
|
||||
|************************************************************|
|
||||
|
||||
User Defined Variables
|
||||
Some kind of GUI box displaying both the names and values of
|
||||
variables that the user has defined using the expression box
|
||||
above or the financial variables entry boxes. The variables
|
||||
are used to store values for future use/reference
|
||||
|
||||
|
||||
Effective Date: ==mm/dd/yyyy==
|
||||
Initial Payment date: ==mm/dd/yyyy==
|
||||
|------------------------------------------------------------------------|
|
||||
|
||||
Note: the drop down boxes for Compounding Frequency and Payment
|
||||
Frequency should contain the following selectable values:
|
||||
|
||||
annual 1
|
||||
semi-annual 2
|
||||
tri-annual 3
|
||||
quarterly 4
|
||||
bi-monthly 6
|
||||
monthly 12
|
||||
semi-monthly 24
|
||||
bi-weekly 26
|
||||
weekly 52
|
||||
daily (360) 360
|
||||
daily (365) 365
|
||||
|
||||
with the corresponding values used for CF and PF as indicated.
|
||||
|
||||
Clicking on "Discrete Compounding" switches back and forth between
|
||||
"Discrete Compounding" and "Continuous Compounding". "Discrete
|
||||
Compounding" should be the default since it is by far the most common.
|
||||
|
||||
Clicking on "End of Period Payments" switches back and forth between
|
||||
"End of Period Payments" and "Beginning of Period Payments". "End of
|
||||
Period Payments" should probably be the default since it is by far the
|
||||
most common.
|
||||
|
||||
The user could click on the entry box under "Number of Payment
|
||||
Periods", "Interest rate", "Present Value", "Periodic Payment"
|
||||
and "Future Value" and enter a value or expression string to be
|
||||
evaluated. Clicking on the corresponding "Compute" button would
|
||||
compute that financial variable. I have made the entry boxes long so
|
||||
that a user could enter a fairly long string. The boxes could also be
|
||||
made scrollable. The entry function could be made simple and always
|
||||
regard the entry as a string and pass the string to the
|
||||
parser/evaluator to return the appropriate value.
|
||||
|
||||
The titles for the boxes, especially "Present Value" and "Future
|
||||
Value", may need to be changed depending on the feedback from the
|
||||
gnucash community. I have always used those names since they are
|
||||
"generic" and represent all of the possible uses for the financial
|
||||
calculator. In this way a single calculator GUI could be used instead
|
||||
of inventing a GUI for mortgages, another for CDs, another for saving
|
||||
accounts, another for annuities, another for sinking funds, etc.
|
||||
|
||||
The next question is the Amortization Schedule Interface. This
|
||||
interface should not be available until all of the financial variables
|
||||
are known. Once they are, the user should be able to click on a "tab"
|
||||
or something to get the Amortization Schedule Interface. A first stab
|
||||
at such an interface could be as shown below. Once the financial
|
||||
variables are known - either all entered by the user or one computed
|
||||
as indicated by the user, the function "Amortization_init" would be
|
||||
called to compute the quatities needed for the user to choose which
|
||||
amortization schedule is desired. The function "amort_opt" in the
|
||||
file amort_opt.c contains all of the information that the user must
|
||||
have to decide which of the six schedules is desired.
|
||||
|
||||
Note that the function "Amortization_init" needs two dates:
|
||||
Effective Date of Transaction -- the date the papers were signed, etc.
|
||||
Initial Payment Date -- self explanatory
|
||||
|
||||
Both dates could be initially filled in by the interface with default
|
||||
values. For the Effective Date, the current date would probably be the
|
||||
most likely candidate. The default Initial Payment Date would depend
|
||||
on whether the payments were being made at the beginning or end of the
|
||||
payment periods, i.e., bep in the financial information structure
|
||||
above.
|
||||
|
||||
bep == TRUE, use the first day of the next month for the default
|
||||
Initial Payment Date, e.g., if current day is August 6, 2000,
|
||||
then the default Initial Payment Date would be September 1, 2000
|
||||
bep == FALSE, use if the first day of the month after the next month,
|
||||
e.g., if current day is August 6, 2000, then the default Initial
|
||||
Payment Date would be October 1, 2000
|
||||
|
||||
The user could then change or accept the default dates as desired.
|
||||
|
||||
The only real checking that would need to be done on either date is to
|
||||
insure that the Effective Date preceeds the Initial Payment Date.
|
||||
|
||||
|
||||
The following functions are used for amortization schedules. All
|
||||
functions use the amortization structure defined in "finvar.h",
|
||||
"amort_sched".
|
||||
|
||||
Notice that some of the information is duplication of the infomation
|
||||
used by the financial calculator structure. I thought this best in
|
||||
order to "separate" these two functions so that if a new set of
|
||||
financial variables is desired by the user, the old set used by the
|
||||
amortization computation functions would still be available. The
|
||||
amount of storage is minimal.
|
||||
|
||||
Note that the amortization schedule structure, "amort_sched" is
|
||||
divided into three parts.
|
||||
|
||||
The first part is information set by the calling function(s) and is
|
||||
the financial information from the financial information structure
|
||||
supplemented with the Effective Date and Initial Payment Date
|
||||
information.
|
||||
|
||||
The second part is also set by the calling function(s) and sets which
|
||||
schedule and type of schedule is computed.
|
||||
|
||||
The third part is information set by the amortization functions. Some
|
||||
of the information is needed for the GUI below for selecting which
|
||||
amortization option to compute.
|
||||
|
||||
|
||||
Amortization Schedule Selection GUI:
|
||||
|----------------------------------------------------------------------------|
|
||||
Amortization Schedule
|
||||
|
||||
Effective Date: mm/dd/yyyy
|
||||
Initial Payment date: mm/dd/yyyy
|
||||
|
||||
The Original Present Value is: xxxxxx.xx (pv)
|
||||
The Original Periodic Payment is: xxxx.xx (pmt)
|
||||
The Original Future Value is: xxxx.xx (fv)
|
||||
|
||||
The Delayed Present Value is: xxxxxx.xx (pve)
|
||||
The New Periodic Payment is: xxxx.xx (new_pmt)
|
||||
|
||||
The amortization options are:
|
||||
|
||||
|| Amortize with Original Present Value
|
||||
Constant Payment to Principal: xxxxx.xx (cmpt1)
|
||||
and final payment: xxxxx.xx (final_pmt_opt_1)
|
||||
|
||||
|| Amortize with Delayed Present Value
|
||||
Constant Payment to Principal: xxxxx.xx (cmpt2)
|
||||
and final payment: xxxxx.xx (final_pmt_opt_2)
|
||||
|
||||
|| Amortize with Original Transaction Values
|
||||
and final payment: xxxxx.xx (final_pmt_opt_3)
|
||||
|
||||
|| Amortize with Delayed Present Value, Original Periodic Payment
|
||||
and final payment: xxxxx.xx (final_pmt_opt_4)
|
||||
|
||||
|| Amortize with Delayed Present Value, New Periodic Payment
|
||||
and final payment: xxxxx.xx (final_pmt_opt_5)
|
||||
|
||||
|| Amortize with Original Present Value, Original Periodic Payment
|
||||
new number of total payments: xxx (new_n)
|
||||
and final payment: xxxxx.xx (final_pmt_opt_6)
|
||||
|
||||
|----------------------------------------------------------------------------|
|
||||
|
||||
Note: I have included in parenthesis above the names of the variables
|
||||
in the amortization structure, amort_sched, to be used in filling in
|
||||
the appropriate values. Do not include the parenthesized infomation in
|
||||
the GUI.
|
||||
|
||||
Note: the last option is available ONLY IF the variable "new_n" in the
|
||||
amortization schedule structure is non-zero. If "new_n" is zero, the
|
||||
last option could be "faded out" or left out completely.
|
||||
|
||||
Note that the options are mutually exclusive, picking one turns the
|
||||
others off. Initially all should probably be off, thus forcing the
|
||||
user to pick one.
|
||||
|
||||
Option 3 above is probably the one most likely to be selected by most
|
||||
people. The others are more likely to be choosen as comparisons to
|
||||
what is likely to be dictated by their lending institution which would
|
||||
more than likely be option 3 (at least in the US).
|
||||
|
||||
I have laid out the above options to correspond to the values for the
|
||||
variable "option" in the "amort_sched" structure. Any other sequence
|
||||
could be used so long as the proper numbering is maintained for
|
||||
"option".
|
||||
|
||||
Once a particular option, 1 to 6 inclusive, has been choosen above by
|
||||
the user, they have one more choice to make: namely whether they want
|
||||
an annual summary or a schedule of each payment. Also if "option" is
|
||||
3, 4, 5 or 6 they also have the additional choices of whether they
|
||||
want a fixed prepayment to principal or a variable prepayment to
|
||||
principal schedule. If they choose a fixed prepayment schedule, then
|
||||
they must enter the amount of the fixed prepayment. It's not as
|
||||
complicated as it sounds. The dialog for these choices could look
|
||||
something like:
|
||||
|
||||
|----------------------------------------------------------------------------|
|
||||
|
||||
Type of Amortization Schedule
|
||||
|
||||
|| Annual Summary
|
||||
|
||||
|| Per Payment Schedule
|
||||
|
||||
|| Variable Prepayment to Principal
|
||||
|
||||
|| Fixed Prepayment to Principal Schedule
|
||||
==xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
|
||||
|
||||
|----------------------------------------------------------------------------|
|
||||
|
||||
Note that zero for the fixed prepayment is valid. The value entered
|
||||
(or not entered as the case may be) should be set into the variable,
|
||||
"fixed_pmt" in the amortization schedule structure. If a value for the
|
||||
fixed prepayment is entered by the user, this value should probably be
|
||||
set into "fixed_pmt", irregardless of whether the user selects the
|
||||
fixed prepayment option.
|
||||
|
||||
Note that the options are mutually exclusive, picking one turns the
|
||||
others off. Initially all should probably be off, thus forcing the
|
||||
user to pick one.
|
||||
|
||||
The last two options would only be available if they had selected
|
||||
options 3, 4, 5 or 6 from the amortization options dialog. The
|
||||
information from this dialog would be used to set the variable
|
||||
"summary" in the "amort_sched" structure. The permissable values are:
|
||||
|
||||
'y' -- indicates an annual summary schedule, first option above
|
||||
'p' -- indicates a per payment schedule, option 2 above
|
||||
'a' -- indicates a variable prepayment schedule, option 3 above
|
||||
'f' -- indicates a fixed prepayment schedule, option four above.
|
||||
|
||||
I have provided a function, "amort_opt", in the file "amort_opt.c" to
|
||||
demonstrate which information is used to fill in the appropriate
|
||||
places in the above two GUIs. You can use this function as a guide.
|
||||
|
||||
Once all of that information has been gathered from the user,
|
||||
the amortization schedule can be computed. The function
|
||||
"Amortization_Schedule" is called and does the computation, but not
|
||||
the display/output of the schedule. I orginally had the output of the
|
||||
schedule integrated in this function, but decided that was a dumb
|
||||
idea. Passing back a pointer in the "amort_sched" structure for
|
||||
all of the computed values was a better idea. This way the actual
|
||||
output/display of the schedule can be tailered as desired.
|
||||
|
||||
I have provided the function "amort_prt" in the file "amort_prt.c" as
|
||||
a guide on how to use the structures and the information they contain
|
||||
to display/output the desired schedule. Currently, the function
|
||||
"prints" the information to a specified file. I could alter the
|
||||
function to output HTML tables if desired. The changes would not be
|
||||
very great. Also, a flag could be passed to indicate whether HTML or
|
||||
plain text was desired. Or the function could be completely rewritten
|
||||
to output some completely different format as desired.
|
||||
|
||||
The functions used for the amortization schedule are:
|
||||
|
||||
Amortization_init -- this functions initializes the information for
|
||||
the schedule so that the user can decide which
|
||||
schedule and which type is desired.
|
||||
|
||||
Amortization_Schedule -- this function computes the desired
|
||||
amortization schedule.
|
||||
|
||||
Amortization_free -- this function is called to free the dynamically
|
||||
allocated memory in the amortization schedule - it
|
||||
does not free the amortization schedule structure passed,
|
||||
but the schedule structures allocated by the call to
|
||||
"Amortization_Schedule" and pointed to in the union
|
||||
in the amortization schedule structure.
|
||||
|
||||
amort_opt - a function to display the options to the user and input which
|
||||
schedule and which type is desired. Uses a text display - for
|
||||
guidance in designing the eventual GUI used.
|
||||
|
||||
amort_prt - a function to print the desired schedule, again for guidance
|
||||
in how to use the information computed for each type of schedule.
|
||||
|
||||
|
||||
A typical sequence would be:
|
||||
|
||||
1: use the financial calculator functions to enter/calculate the
|
||||
financial variables
|
||||
|
||||
2: copy the financial information from the financial information
|
||||
structure to the amortization schedule structure
|
||||
|
||||
3: call the "Amortization_init" function to initialize the amortization
|
||||
schedule
|
||||
|
||||
4: obtain from the user, schedule option and type -- "amort_opt" function
|
||||
for command line version
|
||||
|
||||
5: call the "Amortization_Schedule" function to compute the desired
|
||||
amortization schedule
|
||||
|
||||
6: display/output the desired amortization schedule -- "amort_prt"
|
||||
function for the command line version
|
||||
|
||||
7: call the "Amortization_free" function to free memory in computed schedule
|
||||
|
||||
8: loop back to step 4 above for another schedule using same financial
|
||||
data and dates
|
||||
|
||||
9: loop back to step 1 above for new financial data
|
||||
|
||||
|
||||
Right now the documentation is written around the use of the financial
|
||||
calculator in QTAwk, my personal implementation of a superset of awk,
|
||||
nawk and gawk. The document, especially the examples section, will
|
||||
have to be rewritten to a small extent for gnucash. I would like to
|
||||
defer this until we have settled on the GUI since that will determine
|
||||
the end document.
|
||||
|
||||
The examples illustrate the general nature of the calculator and the
|
||||
many "seemingly" unrelated uses for it. I used CA Simply Money under
|
||||
OS/2 for many years. They had several "calculators". At first I
|
||||
thought that was great. Then I really looked at what they had - it was
|
||||
really just many different GUIs for the same calculator, The same
|
||||
calculator under different guises. I stopped using all of theirs very
|
||||
quickly and developed my own since having it all in one was much
|
||||
easier to understand. It also underscored the power of the finanacial
|
||||
functions in everyday life.
|
||||
|
||||
<<<<<<<<<<------------------------------------------------------------>>>>>>>>
|
||||
|
||||
The only thing left to describe is the expression parser/evaluator.
|
||||
The expression parser/evaluator is contained in the file
|
||||
"expression_parser.c".
|
||||
|
||||
Before describing the parser per se, I want to describe the structures
|
||||
used to contain the results returned from the parser. The structure is
|
||||
defined in "finvar.h":
|
||||
|
||||
typedef struct var_store *var_store_ptr;
|
||||
|
||||
typedef struct var_store {
|
||||
unsigned char *variable_name; /* variable name if variable,
|
||||
NULL otherwise */
|
||||
unsigned char use_flag; /* flag if variable has been assigned to */
|
||||
unsigned char assign_flag; /* flag if variable is used */
|
||||
void *value; /* pointer to imp[lementation defined
|
||||
numeric value */
|
||||
var_store_ptr next_var; /* pointer to next variable in linked
|
||||
list */
|
||||
} var_store;
|
||||
|
||||
The "use_flag" variable is for internal use of the parser and can be
|
||||
ignored by the user. The "variable_name" variable possibly points to
|
||||
a string containing the name of the value returned, a "variable
|
||||
name". If NULL, then this is a temporary value. The "value" variable
|
||||
points to a user defined structure containing the numeric value of the
|
||||
variable.
|
||||
|
||||
In designing and writing the parser, I decided early on that the
|
||||
parser should be an "expression parser/evaluator" and that the actual
|
||||
arithmetic was the responsibility of the caller/user. In reading the
|
||||
debate on "gnucash-devel" and realizing that the exact numeric
|
||||
representation used in gnucash was very probably going to be changing
|
||||
in the future, I decided that the parser should be totally independent
|
||||
of the numeric representation used, and thus the exact details of how
|
||||
the arithmetic was performed. To accomplish this, four functions are
|
||||
supplied by the user/caller:
|
||||
|
||||
1: trans_numeric - this function translates the text string into a
|
||||
numeric in the desired representation and returns a pointer to
|
||||
the representation as a (void *) this function has three parameters
|
||||
passed:
|
||||
1: digit_str -- the actual text string of the numeric to be converted
|
||||
to the internal representation
|
||||
2: radix_point -- the ASCII character used to represent the radix point
|
||||
3: rstr -- a pointer to a location in which to return a pointer to the
|
||||
first character not part of the numeric string translated
|
||||
If this pointer is NULL, do not return a value. This parameter
|
||||
is the same as the second parameter of the standard C library
|
||||
functions "strtod" or "strtol"
|
||||
|
||||
2: numeric_ops - this function does the actual arithmetic on two numeric
|
||||
quantities in internal representation. It has three
|
||||
parameters passed:
|
||||
1: op_sym -- the numeric operation to be performed. The possible
|
||||
values are defined in "finvar.h" and are:
|
||||
ADD_OP - addition
|
||||
SUB_OP - subtraction
|
||||
DIV_OP - division
|
||||
MUL_OP - multiplication
|
||||
ASN_OP - assignment
|
||||
2: left_value - the left hand operand of the binary operator
|
||||
3: right_value - the right hand operand of the binary operator
|
||||
Note: left_value and right_value are passed as
|
||||
(void *). This function is responsible for casting
|
||||
to the proper type to use.
|
||||
|
||||
Note: this function should make no assumptions about
|
||||
overwriting or re-using either left_value or
|
||||
right_value, except for ASN_OP. Both values passed
|
||||
must be left unchanged by any operation except ASN_OP.
|
||||
This function is also responsible for allocating/freeing
|
||||
memory as necessary to perform the designated function
|
||||
and returning the result.
|
||||
|
||||
I STRONGLY suggest that the result be returned in
|
||||
dynamically allocated memory. If static memory is used,
|
||||
the parser has no means of copying the returned result
|
||||
or managing static memory to prevent overwriting
|
||||
the result and invalidating the result.
|
||||
|
||||
3: negate_numeric - this function negates the value passed (as a (void *))
|
||||
|
||||
4: free_numeric - this function is responsible for freeing memory used by
|
||||
the internal numeric representation.
|
||||
|
||||
I have included the file "numeric_ops.c" containing the above
|
||||
functions for the usual "double" and "int" representation of
|
||||
numerics. The functions perform integer or floating point operations
|
||||
as appropriate for the string entered by the user. The division
|
||||
operation is done in "double" since I do not think that anybody really
|
||||
wants (9 / 2) to equal 4 instead of 4.5 for financial operations.
|
||||
These functions use the structure defined in finvar.h:
|
||||
|
||||
typedef struct numeric *numeric_ptr;
|
||||
typedef struct numeric {
|
||||
unsigned char type; /* designates type of value */
|
||||
union {
|
||||
long int int_value; /* long integer value */
|
||||
double dbl_value; /* double value */
|
||||
} value;
|
||||
} numeric;
|
||||
|
||||
to contain all numeric values. The variable "type" in this structure
|
||||
can have the values:
|
||||
INT_TYPE
|
||||
DBL_TYPE
|
||||
which are defined in "finvar.h".
|
||||
|
||||
All "named variables", variables defined by the user for storing
|
||||
intermediate results for future reference/use, and temporary variables
|
||||
used by the parser use the variable storage structure, var_store,
|
||||
defined above. The result of parsing and evaluating the string passed
|
||||
are returned in a variable storage structure specified by the caller.
|
||||
|
||||
If the returned variable value is not named, i.e., "variable_name ==
|
||||
NULL", then the user/caller is responsible for freeing the memory used
|
||||
by the internal representation of the numeric value. If, however,
|
||||
"variable_name != NULL", freeing the memory used by the internal
|
||||
numeric representation will cause a segmentation fault later, when
|
||||
parser attempts to free the memory through a call to
|
||||
the "free_numeric". In addition, freeing the memory will probably
|
||||
invalidate the numeric value contained therein and lead to pernicuous
|
||||
results when the value is used.
|
||||
|
||||
If "variable_name != NULL", the user/caller should never attempt to
|
||||
free this memory, that is the sole responsibility of the parser.
|
||||
|
||||
It may be that the calling function has certain "variables" that need
|
||||
to be "pre-defined" for the user to manipulate. The demo financial
|
||||
calculator "pre-defines" the financial variables, "n, i, pv, pmt, fv,
|
||||
CF, PF, disc and bep". I would suggest that the gnucash financial
|
||||
calculator also pre-define these for direct manipulation by the user
|
||||
if they so desire. Other modules of gnucash could pre-define other
|
||||
variables with common names used in accounting if they so desire. This
|
||||
would allow knowledgable users quick access to such values and to be
|
||||
able to easly manipulate the values to obtain desired results. One
|
||||
method of "pre-defining" variables is illustrated in the
|
||||
"fin-interactive.c" file for the demo interactive financial
|
||||
calculator. In essence the function "pre-defining" variables sets up
|
||||
a linked list of variable storage structures with the proper "names"
|
||||
and numeric values. The number of "pre-defined" variables and a
|
||||
pointer to the structure array is passed to the parser in the
|
||||
initialization call. After the parser is eventually exited, the
|
||||
calling function is responsible for freeing any memory used by the
|
||||
"pre-defined" variables and their final numeric representation.
|
||||
|
||||
I think the use of "named variables" and "pre-defined" variables could
|
||||
become very useful in gnucash eventually as people get used to the
|
||||
idea. It may be useful to allow users to define variables with values
|
||||
convienent to them and that are persistent across invocations of
|
||||
gnucash.
|
||||
|
||||
A second design goal of the parser was that it should be callable
|
||||
concurrently by multiple modules within gnucash independently. That
|
||||
each module should be capable of using differing "pre-defined"
|
||||
variables and user defined variables and even internal numeric
|
||||
representations. To that end the calling module must first initialize
|
||||
the parser with a call to "init_parser". This call creates the parser
|
||||
internal structure for subsequent calls to the parser proper. The
|
||||
structure created and returned must then be passed to subsequent calls
|
||||
to the parser. When no further calls to the parser are to be made,
|
||||
the module then calls "exit_parser" with the pointer returned by
|
||||
"init_parser", so that the parser may release dynamically allocated
|
||||
memory.
|
||||
|
||||
The parser recognizes the following binary operators:
|
||||
+
|
||||
-
|
||||
/
|
||||
*
|
||||
=
|
||||
+=
|
||||
-=
|
||||
/=
|
||||
*=
|
||||
|
||||
In addition, the unary operators
|
||||
+
|
||||
-
|
||||
|
||||
are recognized. All numerics are initially recognized as positive
|
||||
numbers. If negative, the unary '-' operator is applied. This saves
|
||||
the logic of having to recogize strings as
|
||||
|
||||
-123
|
||||
|
||||
The logic recognizes "-" and "123" separately. The '-' unary operator
|
||||
is then applied to negate the numeric. This also has the advanatge
|
||||
that the same logic can be used for
|
||||
|
||||
-123
|
||||
+123.45
|
||||
+uvar
|
||||
-uvar
|
||||
|
||||
In each case, the appropriate unary operator is applied to obtain the
|
||||
desired result with no increase in the parsing logic. Thus keeping
|
||||
things as simple as possible.
|
||||
|
||||
The parser also follows the C practice that the assignment operators
|
||||
return a value. Thus, allowing multiple assignments and assignment
|
||||
within expressions. The following expressions are all valid:
|
||||
nni = 123
|
||||
hnk = nni = 23.45
|
||||
jkl = 5 * (nj = 68.9)
|
||||
|
||||
The first time variables are used in an expression, they are
|
||||
initialized to zero, 0. Thus, even if the following variables have not
|
||||
been assigned a value previously, the following expressions are valid:
|
||||
|
||||
nni *= 123
|
||||
above results in zero in nni
|
||||
jk += 45.6
|
||||
above results in 45.6 in jk
|
||||
56.8 - tyh
|
||||
result of above is 56.8
|
||||
tgh - 45.7
|
||||
above the same as
|
||||
-45.7
|
||||
|
||||
After parsing the above expressions the variables nni, jk, tyh and tgh
|
||||
would all be defined.
|
||||
|
||||
There are six functions needed to use the parser/evaluator:
|
||||
|
||||
Note: in the last five functions, in the function paramter (parse_env_ptr pe),
|
||||
"pe" is the pointer returned by the "init_parser" function.
|
||||
|
||||
parser_env_ptr
|
||||
init_parser(var_store_ptr predefined_vars,
|
||||
unsigned char radix_point,
|
||||
void *trans_numeric(unsigned char *digit_str,
|
||||
unsigned char radix_point,
|
||||
unsigned char **rstr),
|
||||
void *numeric_ops(unsigned char op_sym,
|
||||
void *left_value,
|
||||
void *right_value),
|
||||
void *negate_numeric(void *value),
|
||||
void free_numeric(void *numeric_value));
|
||||
|
||||
This function is called by the gnucash module/function/whatever to
|
||||
initialize the parser. The parser returns a pointer to a structure
|
||||
that contains all relevant information for parsering strings. The
|
||||
pointer is returned as (void *) since all information is and should
|
||||
remain pertinent only to the parser. The calling function(s) should
|
||||
never rely on manipulating any information inside this structure
|
||||
directly, since it may and could change in the future.
|
||||
|
||||
-- The first parameter is a pointer to an array of "pre-defined"
|
||||
variables the caller wishes to use with subsequent calls to
|
||||
the parser.
|
||||
-- The second parameter is the radix character to use in numeric
|
||||
strings in subsequent calls to the parser. The parser needs this
|
||||
information to recognize numeric strings of the form
|
||||
".123", where '.' is the radix.
|
||||
-- The third, fourth, fifth, and sixth parameters are the functions
|
||||
I descibed above for the internal numeric representation desired
|
||||
by the calling function(s).
|
||||
|
||||
void exit_parser(parser_env_ptr pe);
|
||||
|
||||
This function is called to exit the parser and free all dynamically
|
||||
allocated memory used by the parser for an internal stack and user
|
||||
defined variables.
|
||||
|
||||
unsigned get_parse_error(parser_env_ptr pe);
|
||||
|
||||
Whenever the parser encounters an error in parsing/evaluating a
|
||||
string, it returns a NULL pointer instead of a valid pointer to a
|
||||
variable storage structure. This call returns an unsigned integer
|
||||
designating the error encountered. The possible values are defined in
|
||||
the "finvar.h" file. A function "parse_error" has been defined in the
|
||||
file "fin-interactive.c" illustrating how to use this function and
|
||||
pin-point for the user the exact location of the error.
|
||||
|
||||
var_store_ptr get_vars(parser_env_ptr pe)
|
||||
|
||||
This function returns a pointer to a linked list of variable storage
|
||||
structures containing the user defined named variables if any
|
||||
exist. NULL is returned if none exist. An illustration of using this
|
||||
function is contained in the "main" function in the
|
||||
"fin-interactive.c" file. The calling function should not alter the
|
||||
variable names. The numeric values may be altered if the calling
|
||||
function really knows what it is doing.
|
||||
|
||||
unsigned delete_var(unsigned char *var_name,
|
||||
parse_env_ptr pe);
|
||||
|
||||
This function will delete the user defined named variable with a name
|
||||
identical to the name string passed in the first parameter. If no user
|
||||
defined variable exists with an identical name, zero, 0, returned. If
|
||||
the delete operation is successful, one, 1, is returned.
|
||||
|
||||
unsigned char *parse_string(var_store_ptr value,
|
||||
unsigned char *string,
|
||||
parser_env_ptr pe);
|
||||
|
||||
This function parses the string passed in the second parameter and
|
||||
returns a pointer to the last character not recognized upon a parsing
|
||||
error. If no error occurred, NULL is returned. The first parameter
|
||||
specifies a variable storage structure to contain the result of the
|
||||
parser/evaluator.
|
||||
|
||||
Note: The parser/evaluator uses a simple recursive descent parser.
|
||||
I decided on this type for the simple reason that for a simple four
|
||||
function calculator a recursive descent parser is, in my opnion, the
|
||||
easiest to construct. I also think that recursive descent parsers are
|
||||
easier for the human to understand and thus maintain. Since gnucash is
|
||||
open source and will probably have many maintainers in its history,
|
||||
the later point is probably the more relevant.
|
||||
|
||||
Also, the parser uses a stack which is dynamically allocated in memory
|
||||
and can grow as needed. I have not provided any mechanism for
|
||||
shrinking the stack. The initial stack size is set at 50. I really do
|
||||
not anticipate that under normal and even most extreme cases, that it
|
||||
will ever approach that size in actual use. Under "normal" operation,
|
||||
the stack will probably never exceed 3 or 4 in size and 50 is probably
|
||||
an overkill for normal use. However, since the stack is pointers and
|
||||
not entire structures, a stack size of 50 is not that much memory and
|
||||
can be tolerated by most users. Thus, a mechanism for shrinking the
|
||||
stack will probably never be needed.
|
@ -1,151 +0,0 @@
|
||||
/***************************************************************************
|
||||
amort_opt.c - description
|
||||
-------------------
|
||||
begin : Thursday June 15 2000
|
||||
email : tboldt@attglobal.net
|
||||
Author : Terry D. Boldt
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Functions to determine amortizations options
|
||||
* 7-2-2000
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "finvar.h"
|
||||
#include "finproto.h"
|
||||
#include "fin_spl_protos.h"
|
||||
|
||||
amort_sched_ptr amort_opt(
|
||||
amort_sched_ptr amortsched,
|
||||
void *parse_env)
|
||||
{
|
||||
char buffer[200], *errp;
|
||||
unsigned long ii;
|
||||
unsigned prec = amortsched->prec;
|
||||
var_store value;
|
||||
numeric_ptr nval;
|
||||
struct tm *times_E,
|
||||
*times_I;
|
||||
|
||||
/* print amortization options */
|
||||
times_E = (struct tm *)calloc(1, sizeof(struct tm));
|
||||
ii = amortsched->Eff_Date_jdn;
|
||||
times_E->tm_mday = amortsched->day_E;
|
||||
times_E->tm_mon = amortsched->month_E - 1;
|
||||
times_E->tm_year = amortsched->year_E - 1900;
|
||||
times_E->tm_wday = (ii + 1) % 7;
|
||||
times_E->tm_yday = amortsched->yday_E;
|
||||
|
||||
times_I = (struct tm *)calloc(1, sizeof(struct tm));
|
||||
ii = amortsched->Init_Date_jdn;
|
||||
times_I->tm_mday = amortsched->day_I;
|
||||
times_I->tm_mon = amortsched->month_I - 1;
|
||||
times_I->tm_year = amortsched->year_I - 1900;
|
||||
times_I->tm_wday = (ii + 1) % 7;
|
||||
times_I->tm_yday = amortsched->yday_I;
|
||||
|
||||
printf("\n******************************");
|
||||
qof_strftime(buffer, (size_t)50, "%c", times_E);
|
||||
printf("\nEffective Date: %s\n", buffer);
|
||||
qof_strftime(buffer, (size_t)50, "%c", times_I);
|
||||
printf("Initial Payment Date: %s\n", buffer);
|
||||
free(times_E);
|
||||
free(times_I);
|
||||
printf("The Original Present Value (pv) is: %.*f\n", (int)prec, amortsched->pv);
|
||||
printf("The Original Periodic Payment (pmt) is: %.*f\n", (int)prec, amortsched->pmt);
|
||||
printf("The Original Future Value (fv) is: %.*f\n", (int)prec, amortsched->fv);
|
||||
|
||||
printf("The Delayed Present Value (pve) is: %.*f\n", (int)prec, amortsched->pve);
|
||||
printf("The New Periodic Payment (pmt) for pve is: %.*f\n\n", (int)prec, amortsched->new_pmt);
|
||||
|
||||
printf("The amortization options are:\n");
|
||||
printf("1 -- Amortize with Original Amount and Constant Payment to Principal: %.*f\n", (int) prec, amortsched->cpmt1);
|
||||
printf(" and final payment: %.*f\n", (int)prec, amortsched->final_pmt_opt_1);
|
||||
printf("2 -- Amortize with Delayed Amount and Constant Payment to Principal: %.*f\n", (int)prec, amortsched->cpmt2);
|
||||
printf(" and final payment: %.*f\n", (int)prec, amortsched->final_pmt_opt_2);
|
||||
printf("3 -- Amortize with Original Transaction Values\n");
|
||||
printf(" and final payment: %.*f\n", (int)prec, amortsched->final_pmt_opt_3);
|
||||
printf("4 -- Amortize with Delayed Amount, Original Periodic Payment\n");
|
||||
printf(" and final payment: %.*f\n", (int)prec, amortsched->final_pmt_opt_4);
|
||||
printf("5 -- Amortize with Delayed Amount, New Periodic Payment\n");
|
||||
printf(" and final payment: %.*f\n", (int)prec, amortsched->final_pmt_opt_5);
|
||||
if ( amortsched->new_n )
|
||||
{
|
||||
printf("6 -- Amortize with Original Amount, Original Periodic Payment,\n");
|
||||
printf(" new number of total payments (n): %u\n", amortsched->new_n);
|
||||
printf(" and final payment: %.*f\n", (int)prec, amortsched->final_pmt_opt_6);
|
||||
} /* endif */
|
||||
printf("Enter choice 1, 2, 3, 4, 5 or 6: ");
|
||||
fgets(buffer, 190, stdin);
|
||||
amortsched->option = buffer[0] - '0';
|
||||
|
||||
printf("Amortization Schedule:\n");
|
||||
printf("y -- Yearly Summary\n");
|
||||
printf("p -- Periodic Payment\n");
|
||||
if ( amortsched->option < 3 )
|
||||
{
|
||||
printf("Enter Choice y or p: ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("f -- Fixed Advanced Payment\n");
|
||||
printf("a -- Variable Advanced Payment\n");
|
||||
printf("Enter Choice y, p, f or a: ");
|
||||
} /* endif */
|
||||
fgets(buffer, 190, stdin);
|
||||
amortsched->summary = buffer[0];
|
||||
|
||||
if ( amortsched->summary == 'f' )
|
||||
{
|
||||
if ( amortsched->fixed_pmt != 0.0 )
|
||||
{
|
||||
printf("Current Fixed Prepayment: %.*f\nChange Fixed Prepayment? (y/n): ", (int)prec, amortsched->fixed_pmt);
|
||||
fgets(buffer, 190, stdin);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[0] = 'y';
|
||||
} /* endif */
|
||||
|
||||
if ( buffer[0] == 'y' )
|
||||
{
|
||||
printf("Enter Fixed Prepayment Amount: ");
|
||||
fgets(buffer, 190, stdin);
|
||||
if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
|
||||
{
|
||||
nval = (numeric_ptr)(value.value);
|
||||
switch ( nval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
amortsched->fixed_pmt = (double)(nval->value.int_value);
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
amortsched->fixed_pmt = nval->value.dbl_value;
|
||||
break;
|
||||
} /* endswitch */
|
||||
if ( !value.variable_name ) free_numeric(value.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_error(get_parse_error(parse_env), buffer, errp);
|
||||
} /* endif */
|
||||
} /* endif */
|
||||
} /* endif */
|
||||
|
||||
return amortsched;
|
||||
} /* amort_opt */
|
@ -1,307 +0,0 @@
|
||||
/***************************************************************************
|
||||
amort_prt.c - description
|
||||
-------------------
|
||||
begin : Thursday June 15 2000
|
||||
email : tboldt@attglobal.net
|
||||
Author : Terry D. Boldt
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Functions to print amortization schedules
|
||||
* 6-15-2000
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <mcheck.h>
|
||||
|
||||
#include "finvar.h"
|
||||
#include "finproto.h"
|
||||
#include "fin_spl_protos.h"
|
||||
|
||||
|
||||
void prt_amortization_schedule(
|
||||
amort_sched_ptr amortsched, /* amortization schedule to print */
|
||||
FILE *ofile) /* output file */
|
||||
{
|
||||
unsigned j,
|
||||
jj,
|
||||
prec = amortsched->prec,
|
||||
option = amortsched->option,
|
||||
fv_case = amortsched->fv_case;
|
||||
unsigned char datel[100],
|
||||
summary = amortsched->summary;
|
||||
struct tm *times_E,
|
||||
*times_I;
|
||||
amort_sched_yr_ptr amortyr,
|
||||
prst_yr;
|
||||
sched_pmt_ptr pmtsched = NULL;
|
||||
yearly_summary_ptr annual_summary;
|
||||
|
||||
times_E = (struct tm *)calloc(1, sizeof(struct tm));
|
||||
times_E->tm_mday = amortsched->day_E;
|
||||
times_E->tm_mon = amortsched->month_E - 1;
|
||||
times_E->tm_year = amortsched->year_E - 1900;
|
||||
times_E->tm_wday = (amortsched->Eff_Date_jdn + 1) % 7;
|
||||
times_E->tm_yday = amortsched->yday_E;
|
||||
|
||||
times_I = (struct tm *)calloc(1, sizeof(struct tm));
|
||||
times_I->tm_mday = amortsched->day_I;
|
||||
times_I->tm_mon = amortsched->month_I - 1;
|
||||
times_I->tm_year = amortsched->year_I - 1900;
|
||||
times_I->tm_wday = (amortsched->Init_Date_jdn + 1) % 7;
|
||||
times_I->tm_yday = amortsched->yday_I;
|
||||
|
||||
fprintf(ofile, "Amortization Table\n");
|
||||
qof_strftime(datel, (size_t)100, "%c", times_E);
|
||||
fprintf(ofile, "Effective Date: %s\n", datel);
|
||||
qof_strftime(datel, (size_t)100, "%c", times_I);
|
||||
fprintf(ofile, "Initial Payment Date: %s\n", datel);
|
||||
fprintf(ofile, "Compounding Frequency per year: %u\n", amortsched->CF);
|
||||
fprintf(ofile, "Payment Frequency per year: %u\n", amortsched->PF);
|
||||
fprintf(ofile, "Compounding: %s\n", (amortsched->disc ? "Discrete" : "Continuous"));
|
||||
fprintf(ofile, "Payments: %s\n", (amortsched->bep ? "Beginning of Period" : "End of Period"));
|
||||
fprintf(ofile, "Payments (%u): %.*f\n", amortsched->n - 1, (int)prec, (option < 3) ? amortsched->cpmt : (option == 5) ? amortsched->new_pmt : amortsched->pmt);
|
||||
fprintf(ofile, "Final payment (%u): %.*f\n", amortsched->n, (int)prec, amortsched->final_pmt);
|
||||
if ( (amortsched->CF == 1) && (amortsched->PF == 1) ) fprintf(ofile, "Nominal Interest per Payment Period: %g\t(Annualized: %g)\n", amortsched->nint, amortsched->nint * 12);
|
||||
else fprintf(ofile, "Nominal Annual Interest Rate: %g\n", amortsched->nint);
|
||||
fprintf(ofile, " Effective Interest Rate Per Payment Period: %g\n", amortsched->eint);
|
||||
fprintf(ofile, "Present Value: %.*f\n", (int)prec, amortsched->pv);
|
||||
if ( (amortsched->option == 2) || (amortsched->option > 3) )
|
||||
{
|
||||
fprintf(ofile, "Interest due to Delayed Intial Payment: %.*f\n", (int)prec, amortsched->delayed_int);
|
||||
} /* endif */
|
||||
|
||||
free(times_E);
|
||||
free(times_I);
|
||||
|
||||
if ( amortsched->option < 3 )
|
||||
{
|
||||
summary = (summary == 'y') ? 'x' : 'o';
|
||||
} /* endif */
|
||||
|
||||
switch ( summary )
|
||||
{
|
||||
case 'a':
|
||||
/* variable prepayment schedule
|
||||
*/
|
||||
fprintf(ofile, "Advanced Prepayment Amortization - Variable Prepayment\n");
|
||||
amortyr = amortsched->schedule.first_yr;
|
||||
for ( j = amortsched->total_periods , jj = 0 ; j && amortyr ; j-- )
|
||||
{
|
||||
if ( !jj )
|
||||
{
|
||||
fprintf(ofile, "Pmt * Interest Principal Prepay Total Pmt Balance\n");
|
||||
pmtsched = amortyr->payments;
|
||||
jj = amortyr->num_periods;
|
||||
} /* endif */
|
||||
|
||||
fprintf(ofile, "%4u %12.*f %12.*f %12.*f %12.*f %12.*f\n",
|
||||
pmtsched->period_num,
|
||||
(int)prec, pmtsched->interest,
|
||||
(int)prec, pmtsched->principal,
|
||||
(int)prec, pmtsched->advanced_pmt,
|
||||
(int)prec, pmtsched->total_pmt,
|
||||
(int)prec, pmtsched->balance);
|
||||
|
||||
if ( !--jj )
|
||||
{
|
||||
fprintf(ofile, "Summary for: %u:\n", amortyr->year);
|
||||
fprintf(ofile, " Interest Paid: %.*f\n", (int)prec, amortyr->interest_pd);
|
||||
fprintf(ofile, " Principal Paid: %.*f\n", (int)prec, amortyr->principal_pd);
|
||||
fprintf(ofile, " Year Ending Balance: %.*f\n", (int)prec, amortyr->yr_end_balance);
|
||||
fprintf(ofile, " Sum of Interest Paid: %.*f\n", (int)prec, amortyr->total_interest_pd);
|
||||
prst_yr = amortyr;
|
||||
amortyr = amortyr->next_yr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pmtsched++;
|
||||
} /* endif */
|
||||
} /* endfor */
|
||||
break;
|
||||
case 'f':
|
||||
/* fixed prepayment schedule
|
||||
*/
|
||||
fprintf(ofile, "Advanced Prepayment Amortization - Fixed Prepayment: %.*f\n", (int)prec, amortsched->fixed_pmt);
|
||||
amortyr = amortsched->schedule.first_yr;
|
||||
for ( j = amortsched->total_periods , jj = 0 ; j && amortyr ; j-- )
|
||||
{
|
||||
if ( !jj )
|
||||
{
|
||||
fprintf(ofile, "Pmt * Interest Principal Prepay Total Pmt Balance\n");
|
||||
pmtsched = amortyr->payments;
|
||||
jj = amortyr->num_periods;
|
||||
} /* endif */
|
||||
|
||||
fprintf(ofile, "%4u %12.*f %12.*f %12.*f %12.*f %12.*f\n",
|
||||
pmtsched->period_num,
|
||||
(int)prec, pmtsched->interest,
|
||||
(int)prec, pmtsched->principal,
|
||||
(int)prec, pmtsched->advanced_pmt,
|
||||
(int)prec, pmtsched->total_pmt,
|
||||
(int)prec, pmtsched->balance);
|
||||
|
||||
if ( !--jj )
|
||||
{
|
||||
fprintf(ofile, "Summary for: %u:\n", amortyr->year);
|
||||
fprintf(ofile, " Interest Paid: %.*f\n", (int)prec, amortyr->interest_pd);
|
||||
fprintf(ofile, " Principal Paid: %.*f\n", (int)prec, amortyr->principal_pd);
|
||||
fprintf(ofile, " Year Ending Balance: %.*f\n", (int)prec, amortyr->yr_end_balance);
|
||||
fprintf(ofile, " Sum of Interest Paid: %.*f\n", (int)prec, amortyr->total_interest_pd);
|
||||
prst_yr = amortyr;
|
||||
amortyr = amortyr->next_yr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pmtsched++;
|
||||
} /* endif */
|
||||
} /* endfor */
|
||||
break;
|
||||
case 'o':
|
||||
/* constant payment to principal
|
||||
*/
|
||||
fprintf(ofile, "Constant Payment to Principal: %.*f\n", (int)prec, amortsched->cpmt);
|
||||
amortyr = amortsched->schedule.first_yr;
|
||||
for ( j = amortsched->total_periods , jj = 0 ; j && amortyr ; j-- )
|
||||
{
|
||||
if ( !jj )
|
||||
{
|
||||
fprintf(ofile, "Pmt# Interest Total Payment Balance\n");
|
||||
pmtsched = amortyr->payments;
|
||||
jj = amortyr->num_periods;
|
||||
} /* endif */
|
||||
|
||||
fprintf(ofile, "%4u %12.*f %12.*f %12.*f\n",
|
||||
pmtsched->period_num,
|
||||
(int)prec, pmtsched->interest,
|
||||
(int)prec, pmtsched->total_pmt,
|
||||
(int)prec, pmtsched->balance);
|
||||
|
||||
if ( !--jj )
|
||||
{
|
||||
fprintf(ofile, "Summary for: %u:\n", amortyr->year);
|
||||
fprintf(ofile, " Interest Paid: %.*f\n", (int)prec, amortyr->interest_pd);
|
||||
fprintf(ofile, " Principal Paid: %.*f\n", (int)prec, amortyr->principal_pd);
|
||||
fprintf(ofile, " Year Ending Balance: %.*f\n", (int)prec, amortyr->yr_end_balance);
|
||||
fprintf(ofile, " Sum of Interest Paid: %.*f\n", (int)prec, amortyr->total_interest_pd);
|
||||
prst_yr = amortyr;
|
||||
amortyr = amortyr->next_yr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pmtsched++;
|
||||
} /* endif */
|
||||
} /* endfor */
|
||||
break;
|
||||
case 'p':
|
||||
/* normal payment schedule
|
||||
*/
|
||||
fprintf(ofile, "Normal Amortization Schedule\n");
|
||||
amortyr = amortsched->schedule.first_yr;
|
||||
for ( j = amortsched->total_periods - 1 , jj = 0 ; j && amortyr ; j-- )
|
||||
{
|
||||
if ( !jj )
|
||||
{
|
||||
fprintf(ofile, amortsched->fv_case ? "Pmt * Interest Balance\n" : "Pmt * Interest Principal Balance\n");
|
||||
pmtsched = amortyr->payments;
|
||||
jj = amortyr->num_periods;
|
||||
} /* endif */
|
||||
|
||||
if ( fv_case )
|
||||
{
|
||||
fprintf(ofile, "%4u %12.*f %12.*f\n",
|
||||
pmtsched->period_num,
|
||||
(int)prec, pmtsched->interest,
|
||||
(int)prec, pmtsched->balance);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(ofile, "%4u %12.*f %12.*f %12.*f\n",
|
||||
pmtsched->period_num,
|
||||
(int)prec, pmtsched->interest,
|
||||
(int)prec, pmtsched->principal,
|
||||
(int)prec, pmtsched->balance);
|
||||
} /* endif */
|
||||
|
||||
if ( !--jj )
|
||||
{
|
||||
fprintf(ofile, "Summary for: %u:\n", amortyr->year);
|
||||
fprintf(ofile, " Interest Paid: %.*f\n", (int)prec, amortyr->interest_pd);
|
||||
if ( !fv_case ) fprintf(ofile, " Principal Paid: %.*f\n", (int)prec, amortyr->principal_pd);
|
||||
fprintf(ofile, " Year Ending Balance: %.*f\n", (int)prec, amortyr->yr_end_balance);
|
||||
fprintf(ofile, " Sum of Interest Paid: %.*f\n", (int)prec, amortyr->total_interest_pd);
|
||||
prst_yr = amortyr;
|
||||
amortyr = amortyr->next_yr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pmtsched++;
|
||||
} /* endif */
|
||||
} /* endfor */
|
||||
|
||||
if ( !jj )
|
||||
{
|
||||
fprintf(ofile, amortsched->fv_case ? "Pmt * Interest Balance\n" : "Pmt * Interest Principal Balance\n");
|
||||
pmtsched = amortyr->payments;
|
||||
} /* endif */
|
||||
|
||||
fprintf(ofile, "Final Payment: %.*f\n", (int)prec, amortyr->final_pmt);
|
||||
|
||||
if ( fv_case )
|
||||
{
|
||||
fprintf(ofile, "%4u %12.*f %12.*f\n",
|
||||
pmtsched->period_num,
|
||||
(int)prec, pmtsched->interest,
|
||||
(int)prec, pmtsched->balance);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(ofile, "%4u %12.*f %12.*f %12.*f\n",
|
||||
pmtsched->period_num,
|
||||
(int)prec, pmtsched->interest,
|
||||
(int)prec, pmtsched->principal,
|
||||
(int)prec, pmtsched->balance);
|
||||
} /* endif */
|
||||
|
||||
fprintf(ofile, "Summary for: %u:\n", amortyr->year);
|
||||
fprintf(ofile, " Interest Paid: %.*f\n", (int)prec, amortyr->interest_pd);
|
||||
if ( !fv_case ) fprintf(ofile, " Principal Paid: %.*f\n", (int)prec, amortyr->principal_pd);
|
||||
fprintf(ofile, " Year Ending Balance: %.*f\n", (int)prec, amortyr->yr_end_balance);
|
||||
fprintf(ofile, " Sum of Interest Paid: %.*f\n", (int)prec, amortyr->total_interest_pd);
|
||||
break;
|
||||
case 'x':
|
||||
/* constant payment to principal - annual summary
|
||||
*/
|
||||
case 'y':
|
||||
/* normal payment - annual summary
|
||||
*/
|
||||
if ( summary == 'x' ) fprintf(ofile, "Annual Summary - Constant Payment to Principal: %.*f\n", (int)prec, amortsched->cpmt);
|
||||
else fprintf(ofile, "Annual Summary - Normal Amortization\n");
|
||||
fprintf(ofile, "Year Interest Ending Balance\n");
|
||||
annual_summary = amortsched->schedule.summary;
|
||||
for ( j = amortsched->total_periods , jj = 0 ; j ; j-- , jj++ )
|
||||
{
|
||||
fprintf(ofile, "%4u %12.*f %12.*f\n",
|
||||
annual_summary[jj].year,
|
||||
(int)prec, annual_summary[jj].interest,
|
||||
(int)prec, annual_summary[jj].end_balance);
|
||||
} /* endfor */
|
||||
break;
|
||||
} /* endswitch */
|
||||
|
||||
fprintf(ofile, "\nTotal Interest: %.*f\n", (int)prec, amortsched->total_interest);
|
||||
|
||||
} /* prt_amortization_schedule */
|
@ -1,600 +0,0 @@
|
||||
/***************************************************************************
|
||||
fin-interactive.c - description
|
||||
-------------------
|
||||
begin : Thursday June 15 2000
|
||||
email : tboldt@attglobal.net
|
||||
Author : Terry D. Boldt
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Functions to interact with user and call financial equations
|
||||
* 6-22-2000
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <mcheck.h>
|
||||
|
||||
#include "finvar.h"
|
||||
#include "finproto.h"
|
||||
#include "fin_spl_protos.h"
|
||||
#include "numeric_ops.h"
|
||||
|
||||
static void prt_status(
|
||||
fi_ptr fi,
|
||||
FILE *ofile);
|
||||
|
||||
static void set_fin_vars(
|
||||
void);
|
||||
|
||||
static void unset_fin_vars(
|
||||
void);
|
||||
|
||||
#define PREDEFINED_FIN_VARS 9
|
||||
|
||||
/* define local financial variables
|
||||
*/
|
||||
static unsigned npp;
|
||||
static double ir;
|
||||
static double pv;
|
||||
static double pmt;
|
||||
static double fv;
|
||||
static unsigned CF;
|
||||
static unsigned PF;
|
||||
static unsigned disc;
|
||||
static unsigned bep;
|
||||
|
||||
/* define local variable for roundoff precesion
|
||||
* default here to value for US currency
|
||||
*/
|
||||
static unsigned prec = 2;
|
||||
|
||||
/* declare array of structures for local financial variables
|
||||
*/
|
||||
static var_store predefined_fin_vars[PREDEFINED_FIN_VARS];
|
||||
|
||||
/* declare array of finacial varibale names used by user to access financial variables
|
||||
*/
|
||||
static char *fin_var_names[] =
|
||||
{
|
||||
"n",
|
||||
"i",
|
||||
"pv",
|
||||
"pmt",
|
||||
"fv",
|
||||
"CF",
|
||||
"PF",
|
||||
"disc",
|
||||
"bep",
|
||||
};
|
||||
|
||||
/* declare array of financial variables
|
||||
*/
|
||||
static void *fin_vars[] =
|
||||
{
|
||||
(void *)&npp,
|
||||
(void *)&ir,
|
||||
(void *)&pv,
|
||||
(void *)&pmt,
|
||||
(void *)&fv,
|
||||
(void *)&CF,
|
||||
(void *)&PF,
|
||||
(void *)&disc,
|
||||
(void *)&bep,
|
||||
};
|
||||
|
||||
/* declare array of financial variable basic numeric types
|
||||
*/
|
||||
static char fin_type[] =
|
||||
{
|
||||
INT_TYPE,
|
||||
DBL_TYPE,
|
||||
DBL_TYPE,
|
||||
DBL_TYPE,
|
||||
DBL_TYPE,
|
||||
INT_TYPE,
|
||||
INT_TYPE,
|
||||
INT_TYPE,
|
||||
INT_TYPE,
|
||||
};
|
||||
|
||||
static char sl_commands[] = "acdqsv";
|
||||
|
||||
/* function to set local financial variables into array for use by expression parser
|
||||
* as pre-defined variables
|
||||
*/
|
||||
static void set_fin_vars(
|
||||
void)
|
||||
{
|
||||
unsigned cntr;
|
||||
numeric_ptr value;
|
||||
|
||||
for ( cntr = 0 ; cntr < PREDEFINED_FIN_VARS ; cntr++ )
|
||||
{
|
||||
predefined_fin_vars[cntr].variable_name = fin_var_names[cntr];
|
||||
predefined_fin_vars[cntr].assign_flag = EOS;
|
||||
predefined_fin_vars[cntr].value = value = (numeric_ptr)calloc(1, sizeof(numeric));
|
||||
predefined_fin_vars[cntr].next_var = &predefined_fin_vars[cntr + 1];
|
||||
switch ( value->type = fin_type[cntr] )
|
||||
{
|
||||
case INT_TYPE:
|
||||
value->value.int_value = *(unsigned *)(fin_vars[cntr]);
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
value->value.dbl_value = *(double *)(fin_vars[cntr]);
|
||||
break;
|
||||
} /* endswitch */
|
||||
} /* endfor */
|
||||
predefined_fin_vars[PREDEFINED_FIN_VARS - 1].next_var = NULL;
|
||||
} /* set_fin_vars */
|
||||
|
||||
/* free storage used by local financial variables
|
||||
*/
|
||||
static void unset_fin_vars(
|
||||
void)
|
||||
{
|
||||
unsigned cntr;
|
||||
numeric_ptr value;
|
||||
|
||||
for ( cntr = 0 ; cntr < PREDEFINED_FIN_VARS ; cntr++ )
|
||||
{
|
||||
free(predefined_fin_vars[cntr].value);
|
||||
} /* endfor */
|
||||
} /* unset_fin_vars */
|
||||
|
||||
/* check variable set by expression parser against local financial variables
|
||||
* and update local values as necessary. Also convert variables to proper type
|
||||
* to reflect the native type of the local variable
|
||||
*/
|
||||
void chk_vars(
|
||||
var_store_ptr predefined_vars,
|
||||
void **var_array,
|
||||
char *var_type,
|
||||
unsigned var_cnt)
|
||||
{
|
||||
unsigned cntr;
|
||||
numeric_ptr value;
|
||||
|
||||
for ( cntr = 0 ; cntr < var_cnt ; cntr++ )
|
||||
{
|
||||
if ( predefined_vars[cntr].assign_flag == ASSIGNED_TO )
|
||||
{
|
||||
predefined_vars[cntr].assign_flag = EOS;
|
||||
value = (numeric_ptr)(predefined_vars[cntr].value);
|
||||
switch ( var_type[cntr] )
|
||||
{
|
||||
case INT_TYPE:
|
||||
switch ( value->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
*(int *)(var_array[cntr]) = value->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
value->value.int_value =
|
||||
*(int *)(var_array[cntr]) = (unsigned)(value->value.dbl_value);
|
||||
value->type = INT_TYPE;
|
||||
break;
|
||||
} /* endswitch */
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
switch ( value->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
value->value.dbl_value =
|
||||
*(double *)(var_array[cntr]) = (double)(value->value.int_value);
|
||||
value->type = DBL_TYPE;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
*(double *)(var_array[cntr]) = value->value.dbl_value;
|
||||
break;
|
||||
} /* endswitch */
|
||||
break;
|
||||
} /* endswitch */
|
||||
} /* endif */
|
||||
} /* endfor */
|
||||
} /* chk_fin_vars */
|
||||
|
||||
/* error encountered by expression parser - output error message
|
||||
* and offending string
|
||||
*/
|
||||
void parse_error(unsigned error_code,
|
||||
char *buf_start,
|
||||
char *buf_err)
|
||||
{
|
||||
char *err_str;
|
||||
unsigned bc = (unsigned)(buf_err - buf_start);
|
||||
|
||||
switch ( error_code )
|
||||
{
|
||||
case UNBALANCED_PARENS:
|
||||
err_str = "Unbalanced Parenthesis\n";
|
||||
break;
|
||||
case STACK_OVERFLOW:
|
||||
err_str = "Stack Overflow\n";
|
||||
break;
|
||||
case STACK_UNDERFLOW:
|
||||
err_str = "Stack Underflow\n";
|
||||
break;
|
||||
case UNDEFINED_CHARACTER:
|
||||
err_str = "Unrecognized Character\n";
|
||||
break;
|
||||
case NOT_A_VARIABLE:
|
||||
err_str = "Need a Variable on Left side of assignment operator, '='\n";
|
||||
break;
|
||||
case NOT_A_FUNC:
|
||||
err_str = "Need a valid Function name.\n";
|
||||
break;
|
||||
|
||||
} /* endswitch */
|
||||
printf(err_str);
|
||||
printf("%s\n", buf_start);
|
||||
if ( bc ) for ( bc - 1 ; bc ; bc-- ) printf(" ");
|
||||
printf("^");
|
||||
/* printf("%s\n",buf_err + 1); */
|
||||
printf("\n");
|
||||
} /* parse_error */
|
||||
|
||||
int main(int argc, char **argv, char **env)
|
||||
{
|
||||
char buffer[200], *errp;
|
||||
size_t sbuf;
|
||||
size_t retcnt;
|
||||
var_store value;
|
||||
var_store_ptr value_list;
|
||||
numeric_ptr nval;
|
||||
unsigned compute,
|
||||
jj,
|
||||
yrE,
|
||||
monthE,
|
||||
dayE,
|
||||
yrI,
|
||||
monthI,
|
||||
dayI;
|
||||
struct tm *times_E,
|
||||
*times_I;
|
||||
void *parse_env;
|
||||
amort_sched amortsched;
|
||||
financial_info fininfo;
|
||||
|
||||
/* check dynamic storage allocation
|
||||
*/
|
||||
/* mtrace(); */
|
||||
set_default(&fininfo);
|
||||
set_fin_vars();
|
||||
parse_env = init_parser(predefined_fin_vars,
|
||||
'.',
|
||||
',',
|
||||
trans_numeric,
|
||||
numeric_ops,
|
||||
negate_numeric,
|
||||
free_numeric);
|
||||
|
||||
npp = fininfo.npp;
|
||||
ir = fininfo.ir;
|
||||
pv = fininfo.pv;
|
||||
pmt = fininfo.pmt;
|
||||
fv = fininfo.fv;
|
||||
CF = fininfo.CF;
|
||||
PF = fininfo.PF;
|
||||
disc = fininfo.disc;
|
||||
bep = fininfo.bep;
|
||||
|
||||
fininfo.prec = prec;
|
||||
|
||||
printf("Single Letter Commands:\na -- amortization schedule\nc -- compute financial variable\nd -- delete variable\ns -- output financial variable status\nq -- quit\nv -- list defined variables\n");
|
||||
for (;;)
|
||||
{
|
||||
printf("<>");
|
||||
retcnt = strlen(fgets(buffer, 190, stdin));
|
||||
if ( (retcnt == 2) && (strchr(sl_commands, buffer[0]) != NULL) )
|
||||
{
|
||||
if ( buffer[0] == 'q' ) break;
|
||||
amortsched.prec = fininfo.prec;
|
||||
switch ( buffer[0] )
|
||||
{
|
||||
case 'a':
|
||||
if ( amortsched.Eff_Date_jdn && amortsched.Init_Date_jdn )
|
||||
{
|
||||
printf("Current Effective year: %u\nCurrent Effective month: %u\nCurrent Effective day: %u\nCurrent Initial year: %u\nCurrent Initial month: %u\nCurrent Initial day %u\n",
|
||||
amortsched.year_E,
|
||||
amortsched.month_E,
|
||||
amortsched.day_E,
|
||||
amortsched.year_I,
|
||||
amortsched.month_I,
|
||||
amortsched.day_I);
|
||||
printf("Change dates ? (y/n) ");
|
||||
fgets(buffer, 190, stdin);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[0] = 'y';
|
||||
} /* endif */
|
||||
if ( buffer[0] == 'y' )
|
||||
{
|
||||
printf("Enter Effective Date - year: ");
|
||||
fgets(buffer, 190, stdin);
|
||||
if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
|
||||
{
|
||||
nval = (numeric_ptr)(value.value);
|
||||
switch ( nval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
amortsched.year_E = nval->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
amortsched.year_E = (unsigned)(nval->value.dbl_value);
|
||||
break;
|
||||
} /* endswitch */
|
||||
if ( !value.variable_name ) free_numeric(value.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_error(get_parse_error(parse_env), buffer, errp);
|
||||
} /* endif */
|
||||
printf("Enter Effective Date - month: ");
|
||||
fgets(buffer, 190, stdin);
|
||||
if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
|
||||
{
|
||||
nval = (numeric_ptr)(value.value);
|
||||
switch ( nval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
amortsched.month_E = nval->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
amortsched.month_E = (unsigned)(nval->value.dbl_value);
|
||||
break;
|
||||
} /* endswitch */
|
||||
if ( !value.variable_name ) free_numeric(value.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_error(get_parse_error(parse_env), buffer, errp);
|
||||
} /* endif */
|
||||
printf("Enter Effective Date - day: ");
|
||||
fgets(buffer, 190, stdin);
|
||||
if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
|
||||
{
|
||||
nval = (numeric_ptr)(value.value);
|
||||
switch ( nval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
amortsched.day_E = nval->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
amortsched.day_E = (unsigned)(nval->value.dbl_value);
|
||||
break;
|
||||
} /* endswitch */
|
||||
if ( !value.variable_name ) free_numeric(value.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_error(get_parse_error(parse_env), buffer, errp);
|
||||
} /* endif */
|
||||
printf("Enter Initial Payment Date - year: ");
|
||||
fgets(buffer, 190, stdin);
|
||||
if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
|
||||
{
|
||||
nval = (numeric_ptr)(value.value);
|
||||
switch ( nval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
amortsched.year_I = nval->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
amortsched.year_I = (unsigned)(nval->value.dbl_value);
|
||||
break;
|
||||
} /* endswitch */
|
||||
if ( !value.variable_name ) free_numeric(value.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_error(get_parse_error(parse_env), buffer, errp);
|
||||
} /* endif */
|
||||
printf("Enter Initial Payment Date - month: ");
|
||||
fgets(buffer, 190, stdin);
|
||||
if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
|
||||
{
|
||||
nval = (numeric_ptr)(value.value);
|
||||
switch ( nval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
amortsched.month_I = nval->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
amortsched.month_I = (unsigned)(nval->value.dbl_value);
|
||||
break;
|
||||
} /* endswitch */
|
||||
if ( !value.variable_name ) free_numeric(value.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_error(get_parse_error(parse_env), buffer, errp);
|
||||
} /* endif */
|
||||
printf("Enter Initial Payment Date - day: ");
|
||||
fgets(buffer, 190, stdin);
|
||||
if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
|
||||
{
|
||||
nval = (numeric_ptr)(value.value);
|
||||
switch ( nval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
amortsched.day_I = nval->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
amortsched.day_I = (unsigned)(nval->value.dbl_value);
|
||||
break;
|
||||
} /* endswitch */
|
||||
if ( !value.variable_name ) free_numeric(value.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_error(get_parse_error(parse_env), buffer, errp);
|
||||
} /* endif */
|
||||
} /* endif */
|
||||
|
||||
amortsched.n = npp;
|
||||
amortsched.nint = ir;
|
||||
amortsched.pv = pv;
|
||||
amortsched.pmt = pmt;
|
||||
amortsched.fv = fv;
|
||||
amortsched.CF = CF;
|
||||
amortsched.PF = PF;
|
||||
amortsched.disc = disc;
|
||||
amortsched.bep = bep;
|
||||
|
||||
Amortization_init(&amortsched);
|
||||
amort_opt(&amortsched, parse_env);
|
||||
|
||||
(void)Amortization_Schedule(&amortsched);
|
||||
prt_amortization_schedule(&amortsched, stdout);
|
||||
Amortization_free(&amortsched);
|
||||
break;
|
||||
case 'c':
|
||||
|
||||
printf("Compute:\nn - 1\ni - 2\npv - 3\npmt - 4\nfv - 5\n1, 2, 3, 4 or 5: ");
|
||||
retcnt = strlen(fgets(buffer, 190, stdin));
|
||||
compute = buffer[0] - '0';
|
||||
|
||||
switch ( compute-- )
|
||||
{
|
||||
case 0: /* all values specified nothing to compute */
|
||||
break;
|
||||
case 1: /* compute number of periods, npp */
|
||||
printf("Computing numbor of periods\n");
|
||||
npp = fi_calc_num_payments(&fininfo);
|
||||
printf("Number of Periods: %u\n", npp);
|
||||
nval = (numeric_ptr)(predefined_fin_vars[compute].value);
|
||||
nval->value.int_value = npp;
|
||||
break;
|
||||
case 2: /* compute interest, ir */
|
||||
printf("Computing interest rate\n");
|
||||
ir = fi_calc_interest(&fininfo);
|
||||
printf("Nominal Interest Rate: %.*f\n", prec, ir);
|
||||
nval = (numeric_ptr)(predefined_fin_vars[compute].value);
|
||||
nval->value.dbl_value = ir;
|
||||
break;
|
||||
case 3: /* compute present value, pv */
|
||||
printf("Computing Present Value\n");
|
||||
pv = fi_calc_present_value(&fininfo);
|
||||
printf("Present Value: %.*f\n", prec, pv);
|
||||
nval = (numeric_ptr)(predefined_fin_vars[compute].value);
|
||||
nval->value.dbl_value = pv;
|
||||
break;
|
||||
case 4: /* compute periodic payment, pmt */
|
||||
printf("Computing periodic payment\n");
|
||||
pmt = fi_calc_payment(&fininfo);
|
||||
printf("Periodic Payment: %.*f\n", prec, pmt);
|
||||
nval = (numeric_ptr)(predefined_fin_vars[compute].value);
|
||||
nval->value.dbl_value = pmt;
|
||||
break;
|
||||
case 5: /* compute future value, fv */
|
||||
printf("Computing Future Value\n");
|
||||
fv = fi_calc_future_value(&fininfo);
|
||||
printf("Future Value: %.*f\n", prec, fv);
|
||||
nval = (numeric_ptr)(predefined_fin_vars[compute].value);
|
||||
nval->value.dbl_value = fv;
|
||||
break;
|
||||
default: /* whoops */
|
||||
break;
|
||||
} /* endswitch */
|
||||
break;
|
||||
case 'd':
|
||||
printf("Enter name of variable to delete: ");
|
||||
retcnt = strlen(fgets(buffer, 190, stdin));
|
||||
buffer[retcnt - 1] = EOS;
|
||||
if ( !delete_var(buffer, parse_env) )
|
||||
{
|
||||
printf("Unable to delete specified variable\n");
|
||||
} /* endif */
|
||||
break;
|
||||
case 's':
|
||||
prt_status(&fininfo,
|
||||
stdout);
|
||||
break;
|
||||
case 'v':
|
||||
for ( value_list = parser_get_vars(parse_env) ; value_list ; value_list = value_list->next_var )
|
||||
{
|
||||
printf("%s: ", value_list->variable_name);
|
||||
nval = (numeric_ptr)(value_list->value);
|
||||
switch ( nval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
printf("%i\n", nval->value.int_value);
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
printf("%.*f\n", prec, nval->value.dbl_value);
|
||||
break;
|
||||
} /* endswitch */
|
||||
} /* endfor */
|
||||
break;
|
||||
} /* endswitch */
|
||||
}
|
||||
else if ( retcnt > 1 )
|
||||
{
|
||||
buffer[retcnt - 1] = EOS;
|
||||
|
||||
if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
|
||||
{
|
||||
if ( value.variable_name ) printf("Variable: %s\n", value.variable_name);
|
||||
nval = (numeric_ptr)(value.value);
|
||||
switch ( nval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
printf("Evaluated Value: %i\n", nval->value.int_value);
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
printf("Evaluated Value: %.*f\n", prec, nval->value.dbl_value);
|
||||
break;
|
||||
} /* endswitch */
|
||||
if ( !value.variable_name ) free_numeric(value.value);
|
||||
chk_vars(predefined_fin_vars, fin_vars, fin_type, PREDEFINED_FIN_VARS);
|
||||
fininfo.npp = npp;
|
||||
fininfo.ir = ir;
|
||||
fininfo.pv = pv;
|
||||
fininfo.pmt = pmt;
|
||||
fininfo.fv = fv;
|
||||
fininfo.CF = CF;
|
||||
fininfo.PF = PF;
|
||||
fininfo.disc = disc;
|
||||
fininfo.bep = bep;
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_error(get_parse_error(parse_env), buffer, errp);
|
||||
} /* endif */
|
||||
} /* endif */
|
||||
} /* endfor */
|
||||
exit_parser(parse_env);
|
||||
unset_fin_vars();
|
||||
} /* main */
|
||||
|
||||
static void prt_status(
|
||||
fi_ptr fi,
|
||||
FILE *ofile)
|
||||
{
|
||||
fprintf(ofile, "<================================>\nCurrent Financial Calculator Status:\n");
|
||||
fprintf(ofile, "Compounding Frequency: (CF) %u\n", fi->CF);
|
||||
fprintf(ofile, "Payment Frequency: (PF) %u\n", fi->PF);
|
||||
fprintf(ofile, "Compounding: %s\n", fi->disc ? "Discrete (disc = TRUE)" : "Continuous (disc = FALSE)");
|
||||
fprintf(ofile, "Payments: %s\n", fi->bep ? "Beginning of Period (bep = TRUE)" : "End of Period (bep = FALSE)");
|
||||
if ( fi->npp > 12 ) fprintf(ofile, "Number of Payment Periods (n): %u\t\t(Years: %u)\n", fi->npp, fi->npp / fi->PF);
|
||||
else fprintf(ofile, "Number of Payment Periods (n): %u\n", fi->npp);
|
||||
if ((fi->CF == 1) && (fi->PF == 1) ) fprintf(ofile, "Nominal Interest per Payment Period (i): %f\t(Annualized: %.*f\n", fi->ir, fi->prec, fi->ir * 12);
|
||||
else fprintf(ofile, "Nominal Annual Interest Rate (i): %.*f\n", fi->prec, fi->ir);
|
||||
/* fprintf(ofile, " Effective Interest Rate Per Payment Period: %f\n",eff_int(nint/100.0,CF,PF)); */
|
||||
fprintf(ofile, "Present Value (pv): %.*f\n", fi->prec, fi->pv);
|
||||
fprintf(ofile, "Periodic Payment (pmt): %.*f\n", fi->prec, fi->pmt);
|
||||
fprintf(ofile, "Future Value (fv): %.*f\n<================================>\n", fi->prec, fi->fv);
|
||||
} /* prt_status */
|
@ -1,160 +0,0 @@
|
||||
/***************************************************************************
|
||||
fin-main.c - description
|
||||
-------------------
|
||||
begin : Thursday June 15 2000
|
||||
email : tboldt@attglobal.net
|
||||
Author : Terry D. Boldt
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Functions to call financial equations and output results
|
||||
* 6-15-2000
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "finvar.h"
|
||||
#include "finproto.h"
|
||||
|
||||
static void prt_status(
|
||||
fi_ptr fi,
|
||||
FILE *ofile);
|
||||
|
||||
int main(int argc, char **argv, char **env)
|
||||
{
|
||||
financial_info fininfo;
|
||||
amort_sched amortsched;
|
||||
|
||||
set_default(&fininfo);
|
||||
fininfo.prec = 2;
|
||||
|
||||
fininfo.npp = 360;
|
||||
fininfo.ir = 8.25;
|
||||
fininfo.pv = 345725.0;
|
||||
|
||||
(void)fi_calc_payment(&fininfo);
|
||||
printf("With npp == %u\n ir == %.*f\n pv == %.*f\n", fininfo.npp, fininfo.prec, fininfo.ir, fininfo.prec, fininfo.pv);
|
||||
printf("------------>Compute pmt: -2597.32\n");
|
||||
prt_status(&fininfo,
|
||||
stdout);
|
||||
|
||||
fi_calc_interest(&fininfo);
|
||||
printf("\n------------>Compute ir\n");
|
||||
prt_status(&fininfo,
|
||||
stdout);
|
||||
|
||||
fi_calc_num_payments(&fininfo);
|
||||
printf("\n------------>Compute npp\n");
|
||||
prt_status(&fininfo,
|
||||
stdout);
|
||||
|
||||
fi_calc_future_value(&fininfo);
|
||||
printf("\n------------>Compute fv\n");
|
||||
prt_status(&fininfo,
|
||||
stdout);
|
||||
|
||||
set_default(&fininfo);
|
||||
|
||||
fininfo.npp = 360;
|
||||
fininfo.ir = 8.25;
|
||||
fininfo.pv = 345725.0;
|
||||
fi_calc_payment(&fininfo);
|
||||
|
||||
printf("\n\n Reset financial variables and compute amortization schedules.\n");
|
||||
printf("First Schedule - ignore delay in first payment and\noutput annual summary\n");
|
||||
|
||||
amortsched.n = fininfo.npp;
|
||||
amortsched.nint = fininfo.ir;
|
||||
amortsched.pv = fininfo.pv;
|
||||
amortsched.pmt = fininfo.pmt;
|
||||
amortsched.fv = fininfo.fv;
|
||||
amortsched.CF = fininfo.CF;
|
||||
amortsched.PF = fininfo.PF;
|
||||
amortsched.disc = fininfo.disc;
|
||||
amortsched.bep = fininfo.bep;
|
||||
amortsched.prec = fininfo.prec;
|
||||
amortsched.year_E = 1999;
|
||||
amortsched.month_E = 6;
|
||||
amortsched.day_E = 15;
|
||||
amortsched.year_I = 1999;
|
||||
amortsched.month_I = 8;
|
||||
amortsched.day_I = 1;
|
||||
amortsched.fixed_pmt = -400;
|
||||
|
||||
(void)Amortization_init(&amortsched);
|
||||
|
||||
amortsched.option = 3;
|
||||
amortsched.summary = 'y';
|
||||
(void)Amortization_Schedule(&amortsched);
|
||||
prt_amortization_schedule(&amortsched, stdout);
|
||||
|
||||
printf("\n\nSecond Schedule - ignore delay in first payment and\noutput schedule for each payment\n");
|
||||
amortsched.summary = 'p';
|
||||
(void)Amortization_Schedule(&amortsched);
|
||||
prt_amortization_schedule(&amortsched, stdout);
|
||||
|
||||
|
||||
printf("\n\nThird Schedule - ignore delay in first payment and\noutput variable advanced prepayment schedule\n");
|
||||
amortsched.summary = 'a';
|
||||
(void)Amortization_Schedule(&amortsched);
|
||||
prt_amortization_schedule(&amortsched, stdout);
|
||||
|
||||
printf("\n\nFourth Schedule - ignore delay in first payment and\noutput fixed prepayment schedule\n");
|
||||
amortsched.summary = 'f';
|
||||
(void)Amortization_Schedule(&amortsched);
|
||||
prt_amortization_schedule(&amortsched, stdout);
|
||||
|
||||
printf("\n\nFifth Schedule - use new payments due to delay and\noutput annual summary\n");
|
||||
amortsched.option = 5;
|
||||
amortsched.summary = 'y';
|
||||
(void)Amortization_Schedule(&amortsched);
|
||||
prt_amortization_schedule(&amortsched, stdout);
|
||||
|
||||
printf("\n\nSixth Schedule - use new payments due to delay and\noutput periodic payment schedule\n");
|
||||
amortsched.option = 5;
|
||||
amortsched.summary = 'p';
|
||||
(void)Amortization_Schedule(&amortsched);
|
||||
prt_amortization_schedule(&amortsched, stdout);
|
||||
|
||||
printf("\n\nSeventh Schedule - use new payments due to delay and\noutput variable prepayment schedule\n");
|
||||
amortsched.option = 5;
|
||||
amortsched.summary = 'a';
|
||||
(void)Amortization_Schedule(&amortsched);
|
||||
prt_amortization_schedule(&amortsched, stdout);
|
||||
|
||||
printf("\n\nEighth Schedule - use new payments due to delay and\noutput fixed prepayment schedule\n");
|
||||
amortsched.option = 5;
|
||||
amortsched.summary = 'f';
|
||||
(void)Amortization_Schedule(&amortsched);
|
||||
prt_amortization_schedule(&amortsched, stdout);
|
||||
Amortization_free(&amortsched);
|
||||
} /* main */
|
||||
|
||||
static void prt_status(
|
||||
fi_ptr fi,
|
||||
FILE *ofile)
|
||||
{
|
||||
fprintf(ofile, "<================================>\nCurrent Financial Calculator Status:\n");
|
||||
fprintf(ofile, "Compounding Frequency: (CF) %u\n", fi->CF);
|
||||
fprintf(ofile, "Payment Frequency: (PF) %u\n", fi->PF);
|
||||
fprintf(ofile, "Compounding: %s\n", fi->disc ? "Discrete (disc = TRUE)" : "Continuous (disc = FALSE)");
|
||||
fprintf(ofile, "Payments: %s\n", fi->bep ? "Beginning of Period (bep = TRUE)" : "End of Period (bep = FALSE)");
|
||||
if ( fi->npp > 12 ) fprintf(ofile, "Number of Payment Periods (n): %u\t\t(Years: %u)\n", fi->npp, fi->npp / fi->PF);
|
||||
else fprintf(ofile, "Number of Payment Periods (n): %u\n", fi->npp);
|
||||
if ((fi->CF == 1) && (fi->PF == 1) ) fprintf(ofile, "Nominal Interest per Payment Period (i): %f\t(Annualized: %.*f\n", fi->ir, fi->prec, fi->ir * 12);
|
||||
else fprintf(ofile, "Nominal Annual Interest Rate (i): %.*f\n", fi->prec, fi->ir);
|
||||
/* fprintf(ofile, " Effective Interest Rate Per Payment Period: %f\n",eff_int(nint/100.0,CF,PF)); */
|
||||
fprintf(ofile, "Present Value (pv): %.*f\n", fi->prec, fi->pv);
|
||||
fprintf(ofile, "Periodic Payment (pmt): %.*f\n", fi->prec, fi->pmt);
|
||||
fprintf(ofile, "Future Value (fv): %.*f\n", fi->prec, fi->fv);
|
||||
} /* prt_status */
|
@ -1,26 +0,0 @@
|
||||
#! /bin/sh
|
||||
#/***************************************************************************
|
||||
# fin-proto.sh - description
|
||||
# -------------------
|
||||
# copyright : (C) 2000 by Terry D. Boldt
|
||||
# email : tboldt@attglobal.net
|
||||
# Author : Terry D. Boldt
|
||||
# ***************************************************************************/
|
||||
#
|
||||
#/***************************************************************************
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU General Public License as published by *
|
||||
# * the Free Software Foundation; either version 2 of the License, or *
|
||||
# * (at your option) any later version. *
|
||||
# * *
|
||||
# ***************************************************************************/
|
||||
#
|
||||
# shell script for creating function prototype files
|
||||
#
|
||||
qtgrep -DHhf cfuncs.exp fin.c expression_parser.c numeric_ops.c amort_opt.c amort_prt.c >protos.out
|
||||
echo Creating Global Prototype File: \"finproto.h\"
|
||||
qtawk -f protos.exp protos.out >finproto.h
|
||||
echo Creating Static Prototype File: \"fin_static_proto.h\"
|
||||
qtawk -f static_protos.exp protos.out >fin_static_proto.h
|
||||
rm -fv protos.out
|
@ -1,36 +0,0 @@
|
||||
n
|
||||
12*30
|
||||
14.75
|
||||
100000
|
||||
|
||||
|
||||
|
||||
|
||||
4
|
||||
n
|
||||
y
|
||||
y
|
||||
opmt=pmt
|
||||
n
|
||||
12*15
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
4
|
||||
n
|
||||
y
|
||||
y
|
||||
pmt-opmt
|
||||
n
|
||||
12*30
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
0
|
||||
y
|
@ -1,103 +0,0 @@
|
||||
Evaluate expression (y/n): Current Value, n: 0
|
||||
Enter new value
|
||||
Current Value, i: 0.00
|
||||
Enter new value
|
||||
Current Value, pv: 0.00
|
||||
Enter new value
|
||||
Current Value, pmt: 0.00
|
||||
Enter new value
|
||||
Current Value, fv: 0.00
|
||||
Enter new value
|
||||
Current Value, CF: 12
|
||||
Enter new value
|
||||
Current Value, PF: 12
|
||||
Enter new value
|
||||
Compute:
|
||||
n - 1
|
||||
i - 2
|
||||
pv - 3
|
||||
pmt - 4
|
||||
fv - 5
|
||||
1,2,3,4 or 5:Computing periodic payment
|
||||
<================================>
|
||||
Current Financial Calculator Status:
|
||||
Compounding Frequency: (CF) 12
|
||||
Payment Frequency: (PF) 12
|
||||
Compounding: Discrete (disc = TRUE)
|
||||
Payments: End of Period (bep = FALSE)
|
||||
Number of Payment Periods (n): 360 (Years: 30)
|
||||
Nominal Annual Interest Rate (i): 14.75
|
||||
Present Value (pv): 100000.00
|
||||
Periodic Payment (pmt): -1244.48
|
||||
Future Value (fv): 0.00
|
||||
Compute Amortization Schedule (y/n)
|
||||
Another example (y/n): Evaluate expression (y/n): Enter Expression
|
||||
Evaluated Value: -1244.48
|
||||
Another expression (y/n): Current Value, n: 360
|
||||
Enter new value
|
||||
Current Value, i: 14.75
|
||||
Enter new value
|
||||
Current Value, pv: 100000.00
|
||||
Enter new value
|
||||
Current Value, pmt: -1244.48
|
||||
Enter new value
|
||||
Current Value, fv: 0.00
|
||||
Enter new value
|
||||
Current Value, CF: 12
|
||||
Enter new value
|
||||
Current Value, PF: 12
|
||||
Enter new value
|
||||
Compute:
|
||||
n - 1
|
||||
i - 2
|
||||
pv - 3
|
||||
pmt - 4
|
||||
fv - 5
|
||||
1,2,3,4 or 5:Computing periodic payment
|
||||
<================================>
|
||||
Current Financial Calculator Status:
|
||||
Compounding Frequency: (CF) 12
|
||||
Payment Frequency: (PF) 12
|
||||
Compounding: Discrete (disc = TRUE)
|
||||
Payments: End of Period (bep = FALSE)
|
||||
Number of Payment Periods (n): 180 (Years: 15)
|
||||
Nominal Annual Interest Rate (i): 14.75
|
||||
Present Value (pv): 100000.00
|
||||
Periodic Payment (pmt): -1382.50
|
||||
Future Value (fv): 0.00
|
||||
Compute Amortization Schedule (y/n)
|
||||
Another example (y/n): Evaluate expression (y/n): Enter Expression
|
||||
Evaluated Value: -138.02
|
||||
Another expression (y/n): Current Value, n: 180
|
||||
Enter new value
|
||||
Current Value, i: 14.75
|
||||
Enter new value
|
||||
Current Value, pv: 100000.00
|
||||
Enter new value
|
||||
Current Value, pmt: -1382.50
|
||||
Enter new value
|
||||
Current Value, fv: 0.00
|
||||
Enter new value
|
||||
Current Value, CF: 12
|
||||
Enter new value
|
||||
Current Value, PF: 12
|
||||
Enter new value
|
||||
Compute:
|
||||
n - 1
|
||||
i - 2
|
||||
pv - 3
|
||||
pmt - 4
|
||||
fv - 5
|
||||
1,2,3,4 or 5:<================================>
|
||||
Current Financial Calculator Status:
|
||||
Compounding Frequency: (CF) 12
|
||||
Payment Frequency: (PF) 12
|
||||
Compounding: Discrete (disc = TRUE)
|
||||
Payments: End of Period (bep = FALSE)
|
||||
Number of Payment Periods (n): 180 (Years: 15)
|
||||
Nominal Annual Interest Rate (i): 14.75
|
||||
Present Value (pv): 100000.00
|
||||
Periodic Payment (pmt): -1382.50
|
||||
Future Value (fv): 0.00
|
||||
Compute Amortization Schedule (y/n)
|
||||
Another example (y/n):
|
@ -1,439 +0,0 @@
|
||||
/***************************************************************************
|
||||
numeric_ops.c - description
|
||||
-------------------
|
||||
begin : Wednesday June 21 2000
|
||||
email : tboldt@attglobal.net
|
||||
Author : Terry D. Boldt
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Functions to execute arthmetic operators on integer and double operands
|
||||
* 6-23-2000
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#define NUMERIC_OPS_STATICS
|
||||
#include "finvar.h"
|
||||
|
||||
static double neg_table[] =
|
||||
{
|
||||
1e-256,
|
||||
1e-128,
|
||||
1e-64,
|
||||
1e-32,
|
||||
1e-16,
|
||||
1e-8,
|
||||
1e-4,
|
||||
1e-2,
|
||||
1e-1,
|
||||
1.0
|
||||
};
|
||||
|
||||
static double pos_table[] =
|
||||
{
|
||||
1e+256,
|
||||
1e+128,
|
||||
1e+64,
|
||||
1e+32,
|
||||
1e+16,
|
||||
1e+8,
|
||||
1e+4,
|
||||
1e+2,
|
||||
1e+1
|
||||
};
|
||||
|
||||
#define MAX_SCALE ((LONG_MAX - 10) / 10)
|
||||
|
||||
/* function to translate ASCII string to numeric format.
|
||||
*
|
||||
* Recognizes either integer numerics or floating point numerics.
|
||||
* Recognizes integers in format:
|
||||
* (sign)digit_sequence
|
||||
* digit_sequence may contain a grouping character, the grouping character is ignored
|
||||
* optional sign == '+' or '-'
|
||||
*
|
||||
* Recognizes floating point in formats:
|
||||
* (sign)digit_sequence.digits(exp)
|
||||
* (sign)digit_sequence.(exp)
|
||||
* (sign)digit_sequence(exp)
|
||||
* (sign).digits(exp)
|
||||
* '.' represents the radix point passed, digit_sequence may contain a grouping character
|
||||
* the grouping character is ignored
|
||||
* optional sign == '+' or '-'
|
||||
* optional exp == ('e' or 'E')(sign)digits
|
||||
*
|
||||
* Terminates on first unrecognized character.
|
||||
*
|
||||
*/
|
||||
void *trans_numeric(
|
||||
const char *str, /* pointer to string to translate */
|
||||
char radix_point, /* radix character */
|
||||
char group_char, /* grouping character to left of radix */
|
||||
char **endstr) /* where to return pointer to first unrecognized character */
|
||||
{
|
||||
double dblval = 0.0;
|
||||
int exp = 0,
|
||||
dchr,
|
||||
err = 0,
|
||||
base = 10;
|
||||
long int inum = 0;
|
||||
unsigned long msdec = 0,
|
||||
lsdec = 0,
|
||||
msscale = 1;
|
||||
unsigned radix = 0,
|
||||
sign = 0,
|
||||
digit_cnt = 0;
|
||||
const char *strinit = str;
|
||||
numeric_ptr rslt = NULL;
|
||||
|
||||
while ( isspace(*str) ) str++;
|
||||
|
||||
switch (*str)
|
||||
{
|
||||
case '-':
|
||||
sign++;
|
||||
case '+':
|
||||
str++;
|
||||
default:
|
||||
break;
|
||||
} /* endswitch */
|
||||
|
||||
while ( *str )
|
||||
{
|
||||
|
||||
while ( (*str >= '0') && (*str <= '9') )
|
||||
{
|
||||
digit_cnt++;
|
||||
|
||||
if ( msdec < MAX_SCALE ) msdec = msdec * 10 + (*str - '0');
|
||||
else if ( msscale < MAX_SCALE )
|
||||
{
|
||||
lsdec = lsdec * 10 + (*str - '0');
|
||||
msscale *= 10;
|
||||
}
|
||||
else exp++;
|
||||
|
||||
if ( radix ) exp--;
|
||||
else
|
||||
{
|
||||
dchr = *str - '0';
|
||||
if ( ((LONG_MIN + dchr) / base) > inum ) err = 1;
|
||||
inum = inum * base + dchr;
|
||||
} /* endif */
|
||||
str++;
|
||||
} /* endwhile */
|
||||
|
||||
if ( !radix )
|
||||
{
|
||||
if ( *str == radix_point ) radix++;
|
||||
else if ( *str != group_char ) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
} /* endif */
|
||||
|
||||
str++;
|
||||
} /* endwhile */
|
||||
|
||||
if ( digit_cnt )
|
||||
{
|
||||
unsigned exp_dcnt = 0;
|
||||
|
||||
if ( (*str == 'e') || (*str == 'E') )
|
||||
{
|
||||
char exp_sign = EOS;
|
||||
int ex_exp = 0;
|
||||
|
||||
switch (*++str)
|
||||
{
|
||||
case '-':
|
||||
exp_sign++;
|
||||
case '+':
|
||||
str++;
|
||||
default:
|
||||
break;
|
||||
} /* endswitch */
|
||||
|
||||
while ( (*str >= '0') && (*str <= '9') )
|
||||
{
|
||||
if (ex_exp < (DBL_MAX_EXP * 2) ) ex_exp = ex_exp * 10 + (*str - '0');
|
||||
str++;
|
||||
exp_dcnt++;
|
||||
} /* endwhile */
|
||||
|
||||
exp += exp_sign ? -ex_exp : ex_exp;
|
||||
} /* endif */
|
||||
|
||||
if ( radix || exp )
|
||||
{
|
||||
int pow = 256;
|
||||
|
||||
dblval = msdec;
|
||||
if ( msscale != 1 ) dblval = dblval * msscale + lsdec;
|
||||
|
||||
if ( dblval && exp )
|
||||
{
|
||||
unsigned u = 0;
|
||||
|
||||
pow = 256;
|
||||
while ( exp > 0 )
|
||||
{
|
||||
while ( exp >= pow )
|
||||
{
|
||||
dblval *= pos_table[u];
|
||||
exp -= pow;
|
||||
} /* endwhile */
|
||||
pow >>= 1;
|
||||
u++;
|
||||
} /* endwhile */
|
||||
|
||||
while ( exp < 0 )
|
||||
{
|
||||
while ( exp <= -pow )
|
||||
{
|
||||
dblval *= neg_table[u];
|
||||
if ( dblval == 0.0 )
|
||||
{
|
||||
errno = ERANGE;
|
||||
err = 1;
|
||||
} /* endif */
|
||||
exp += pow;
|
||||
} /* endwhile */
|
||||
pow >>= 1;
|
||||
u++;
|
||||
} /* endwhile */
|
||||
|
||||
/* if overflow occurred */
|
||||
if ( dblval == HUGE_VAL )
|
||||
{
|
||||
errno = ERANGE;
|
||||
err = 1;
|
||||
} /* endif */
|
||||
} /* endif */
|
||||
|
||||
if ( !err )
|
||||
{
|
||||
rslt = (numeric_ptr)calloc(1, sizeof(numeric));
|
||||
rslt->type = DBL_TYPE;
|
||||
rslt->value.dbl_value = dblval;
|
||||
} /* endif */
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (!sign && (inum == LONG_MIN)) || err )
|
||||
{
|
||||
inum = LONG_MIN + sign;
|
||||
errno = ERANGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rslt = (numeric_ptr)calloc(1, sizeof(numeric));
|
||||
rslt->type = INT_TYPE;
|
||||
rslt->value.int_value = inum;
|
||||
} /* endif */
|
||||
} /* endif */
|
||||
} /* endif */
|
||||
|
||||
if ( endstr )
|
||||
{
|
||||
if ( !digit_cnt ) *endstr = (char *) strinit;
|
||||
else *endstr = (char *) str;
|
||||
} /* endif */
|
||||
|
||||
return (void *)rslt;
|
||||
} /* strtod_flt */
|
||||
|
||||
/* function to free memory used by numeric structure
|
||||
*/
|
||||
void free_numeric(
|
||||
void *numeric_value)
|
||||
{
|
||||
if ( numeric_value ) free(numeric_value);
|
||||
} /* free_numeric */
|
||||
|
||||
/* function to perform unary '-' operation
|
||||
*/
|
||||
void *negate_numeric(
|
||||
void *value)
|
||||
{
|
||||
numeric_ptr rslt = (numeric_ptr)value;
|
||||
|
||||
switch ( rslt->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
rslt->value.int_value = -rslt->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
rslt->value.dbl_value = -rslt->value.dbl_value;
|
||||
break;
|
||||
} /* endswitch */
|
||||
|
||||
return (void *)rslt;
|
||||
} /* negate_numeric */
|
||||
|
||||
/* function to perform binary operators
|
||||
* op_symbol - operation to perform
|
||||
* ADD_OP == perform '+'
|
||||
* SUB_OP == perform '-'
|
||||
* DIV_OP == perform '/'
|
||||
* MUL_OP == perform '*'
|
||||
* ASN_OP == perform '='
|
||||
* l_value - pointer to left hand value
|
||||
* r_value - pointer to right hand value
|
||||
*/
|
||||
void *numeric_ops(
|
||||
char op_symbol,
|
||||
void *l_value,
|
||||
void *r_value)
|
||||
{
|
||||
numeric_ptr lval = (numeric_ptr)l_value,
|
||||
rval = (numeric_ptr)r_value,
|
||||
rslt = (op_symbol == ASN_OP) ? lval : (numeric_ptr)calloc(1, sizeof(numeric));
|
||||
|
||||
switch ( op_symbol )
|
||||
{
|
||||
case ADD_OP:
|
||||
if ( lval->type == rval->type )
|
||||
{
|
||||
rslt->type = lval->type;
|
||||
switch ( lval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
rslt->value.int_value = lval->value.int_value + rval->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
rslt->value.dbl_value = lval->value.dbl_value + rval->value.dbl_value;
|
||||
break;
|
||||
} /* endswitch */
|
||||
}
|
||||
else
|
||||
{
|
||||
rslt->type = DBL_TYPE;
|
||||
switch ( lval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
rslt->value.dbl_value = (double)(lval->value.int_value) + rval->value.dbl_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
rslt->value.dbl_value = lval->value.dbl_value + (double)(rval->value.int_value);
|
||||
break;
|
||||
|
||||
} /* endswitch */
|
||||
} /* endif */
|
||||
break;
|
||||
case SUB_OP:
|
||||
if ( lval->type == rval->type )
|
||||
{
|
||||
rslt->type = lval->type;
|
||||
switch ( lval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
rslt->value.int_value = lval->value.int_value - rval->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
rslt->value.dbl_value = lval->value.dbl_value - rval->value.dbl_value;
|
||||
break;
|
||||
} /* endswitch */
|
||||
}
|
||||
else
|
||||
{
|
||||
rslt->type = DBL_TYPE;
|
||||
switch ( lval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
rslt->value.dbl_value = (double)(lval->value.int_value) - rval->value.dbl_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
rslt->value.dbl_value = lval->value.dbl_value - (double)(rval->value.int_value);
|
||||
break;
|
||||
|
||||
} /* endswitch */
|
||||
} /* endif */
|
||||
break;
|
||||
case DIV_OP:
|
||||
rslt->type = DBL_TYPE;
|
||||
if ( lval->type == rval->type )
|
||||
{
|
||||
switch ( lval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
rslt->value.dbl_value = (double)(lval->value.int_value) / (double)(rval->value.int_value);
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
rslt->value.dbl_value = lval->value.dbl_value / rval->value.dbl_value;
|
||||
break;
|
||||
} /* endswitch */
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( lval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
rslt->value.dbl_value = (double)(lval->value.int_value) / rval->value.dbl_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
rslt->value.dbl_value = lval->value.dbl_value / (double)(rval->value.int_value);
|
||||
break;
|
||||
|
||||
} /* endswitch */
|
||||
} /* endif */
|
||||
break;
|
||||
case MUL_OP:
|
||||
if ( lval->type == rval->type )
|
||||
{
|
||||
rslt->type = lval->type;
|
||||
switch ( lval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
rslt->value.int_value = lval->value.int_value * rval->value.int_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
rslt->value.dbl_value = lval->value.dbl_value * rval->value.dbl_value;
|
||||
break;
|
||||
} /* endswitch */
|
||||
}
|
||||
else
|
||||
{
|
||||
rslt->type = DBL_TYPE;
|
||||
switch ( lval->type )
|
||||
{
|
||||
case INT_TYPE:
|
||||
rslt->value.dbl_value = (double)(lval->value.int_value) * rval->value.dbl_value;
|
||||
break;
|
||||
case DBL_TYPE:
|
||||
rslt->value.dbl_value = lval->value.dbl_value * (double)(rval->value.int_value);
|
||||
break;
|
||||
|
||||
} /* endswitch */
|
||||
} /* endif */
|
||||
break;
|
||||
case ASN_OP:
|
||||
if ( !lval ) lval = (numeric_ptr)calloc(1, sizeof(numeric));
|
||||
lval->type = rval->type;
|
||||
lval->value = rval->value;
|
||||
rslt = lval;
|
||||
break;
|
||||
} /* endswitch */
|
||||
|
||||
|
||||
return (void *)rslt;
|
||||
} /* numeric_ops */
|
@ -1,39 +0,0 @@
|
||||
/***************************************************************************
|
||||
* -------------------
|
||||
* create : Tue Jul 11 20:21:18 2000
|
||||
* copyright: (C) 2000 by Terry D. Boldt
|
||||
* email : tboldt@attglobal.net
|
||||
* -------------------
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
* Global Function Prototypes
|
||||
* Tue Jul 11 20:21:18 2000
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef NUMERIC_OPS_H
|
||||
#define NUMERIC_OPS_H
|
||||
|
||||
void *trans_numeric(const char *str, /* pointer to string to translate */
|
||||
char radix_point, /* radix character */
|
||||
char group_char, /* grouping character to left of radix */
|
||||
char **endstr); /* where to return pointer to first
|
||||
* unrecognized character */
|
||||
|
||||
void free_numeric(void *numeric_value);
|
||||
|
||||
void *negate_numeric(void *value);
|
||||
|
||||
void *numeric_ops(char op_symbol,
|
||||
void *l_value,
|
||||
void *r_value);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user