Problem: You have a bank account whose annual interest rate depends on the amount of money you have in your account at the beginning of each year. Your annual rate starts at 3%, and grows by an additional half a percent for each thousand dollars in your account up to, but not exceeding 8%. So, for example, if you have $3,358.02 in your account at the beginning of the year, your rate is 4.5%. Interest in this account is compounded monthly at the annual rate (i.e. the monthly compounding rate is the annual rate divided by 12). Each year you also make a trasaction (deposit or withdrawal) before the bank figures out what your rate is (fortunately!). Write a program that simulates 5 years under this system, interactively querying the user for transactions at the beginning of each year, and returning the balance at the end of the 5th year.
There's a lot to this problem. However, imagine how much easier it would be to solve if the following functions were available:
double transaction(double B);
- which would
do the interactive
part for you - taking the initial balance B
and
returning the balance after the transaction.
double rate(double B);
- which would return
the interest
rate based on the account balance.
double compound(double r);
- which would give
you the value of
a single dollar after a year's monthly compounding with annual
interest rate r
. If your blance is
B
and your rate is r
at the
beginning of the year, the new balance is
B*compound(r)
.
double B = 0.0; for(int i = 0; i < 5; i++) { B = transaction(B); double r = rate(B); B = B*compound(r); } cout << B << endl;This is a pretty easy program! Of course, the 3 functions in our wish list do not exist, so we'll have to implement them for ourselves.
double transaction(double B) { // Get type of transaction char act; cout << "Enter w: withdrawl d:deposit "; cin >> act; // Get amount of transaction double A; cout << "Enter amount: "; cin >> A; // Get new Balance figure if (act == 'w') B = B - A; else B = B + A; return B; } |
double rate(double B) { // Get # of thousands int T = B/1000; // Calc rate double r = 3 + T*0.5; if (r > 8) r = 8; return r; } |
double compound(double r) { // Sim. year with monthly compounding double R = r/100, total = 1.0; for(int i = 0; i < 12; i++) total = total*(1 + R/12); return total; } |
transaction
, I
don't need to worry about any other aspect of the program - it's
like transaction
is its own little (easy!) program
to write. Take a look at the complete program.
cmath
library, the pow
function. Specifying multiple
parameters for a function is just like spcifying several single
parameters in a comma-separated list. For example, suppose you
wanted to define a function max
that looked at two
int
s and returned the larger of the two. It's
prototype would be
int max(int,int);The definition would look like this:
int max(int a, int b) { if (a < b) return b; else return a; }Note that this example shows you that you can return from anywhere within a function, just like you can return from anywhere within
main
.
It's important to note that the order of arguments is important. For example, suppose you had a function
void rep(int,char);that printed the
char
argument to the screen the
number of times given by the int
. If I want to print
a #
symbol 42 times, I need to be sure to say
rep(42,'#')
, because the function expects the
int
object first. If I said rep('#',42)
instead, do you know what'd happen? I'd print 35 *
s!
Why? Because the same kind of implicit type conversions that go
on inside expressions go on with function arguments! The
rep
function expects an int
as its first
argument, and when it gets '#'
instead, it simply
converts it to an int
... and the ASCII value of
'#'
is 35, so that's the int
you get.
Likewise, a char
is expected as the second argument,
and when rep
gets the number 42 instead, it converts
it to a character, and ASCII value 42 gives you the
char
'*'
.
When implicit conversions aren't possible, the compiler gives
you an error message. For example, if you tried to call
rep("#",42)
the compiler would give you an error
saying that the first argument of rep
was supposed
to be an int
, but you gave it a
string
, and there's no way to convert the
string
to an int
. You'll likely see
lots of these messages in your life!
bool
are
traditionally referred to as predicates. Imagine
that you had to compute more and more terms of a series
approximation for
cos(x)
until your series approximation and the
cmath
library approximation agreed to a particular
precision. In other words, you had two floating-point values and
a number n
and you had to test to see whether they
agreed to within 10^{-n}. We could define a
function approxequal
to do this.
bool approxequal(double, double, int);... where the first two arguments are the quantities to compare, and the
int
argument is the precision.
bool approxequal(double x, double y, int n) { if (fabs(x - y) > pow(10,-n)) return false; else return true; }With the definition of this predicate, the main
while
-loop of you program would look like
while(!approxequal(series,libvalue,n)) { ...
Really there's no need to bring predicates up as a special
subject, since functions that return bool
s are not
any more special than functions that return, say,
string
s. However, you might not have thought much
about the use of having such functions.