The next app uses the for
statement to compute compound interest. Consider the following problem:
A person invests $1,000 in a savings account yielding 5% interest. Assuming that all the interest is left on deposit, calculate and print the amount of money in the account at the end of each year for 10 years. Use the following formula to determine the amounts:
where
p is the original amount invested (i.e., the principal)
r is the annual interest rate (e.g., use 0.05 for 5%)
n is the number of years
a is the amount on deposit at the end of the nth year.
The solution to this problem (Fig. 6.6) involves a loop that performs the indicated calculation for each of the 10 years the money remains on deposit.
Lines 9 and 19 declare decimal
variables principal
and amount
, and line 10 declares double
variable rate
. Lines 9–10 also initialize principal
to 1000
(i.e., $1,000.00) and rate
to 0.05
. C# treats numeric literals like 0.05
as type double
. Similarly, C# treats whole-number literals like 7
and 1000
as type int
—unlike double
values, int
values can be assigned to decimal
variables. When principal
is initialized to 1000
, the int
value 1000
is promoted to type decimal
implicitly—no cast is required. Line 13 outputs the headers for the app’s two columns of output. The first column displays the year, and the second displays the amount on deposit at the end of that year.
pow
Classes provide methods that perform common tasks on objects. Most methods must be called on a specific object. For example, to deposit money into bank accounts in Fig. 4.12, we called method Deposit
on the Account
objects account1
and account2
. Many classes also provide methods to perform common tasks that do not require specific objects—they must be called using a class name. Such methods are called static
methods. You’ve used several static
methods of class Console
—methods Write
, WriteLine
and ReadLine
. You call a static
method by specifying the class name followed by the member-access operator (.
) and the method name, as in
ClassName.MethodName(arguments)
C# does not include an exponentiation operator, so we use class Math
’s static
method Pow
to perform the compound-interest calculation. The expression
Math.Pow(x, y)
calculates the value of x raised to the yth power. The method receives two double
arguments and returns a double
value. Lines 19–20 in Fig. 6.6 perform the calculation
a = p (1 + r)n
from the problem statement, where a is the amount
, p is the principal
, r is the rate
and n is the year
. In this calculation, we need to multiply the decimal
value principal
by a double
value (the value returned by the call to Math.Pow
). C# will not implicitly convert double
to a decimal
type, or vice versa, because of the possible loss of information in either conversion, so line 20 contains a (decimal)
cast operator that explicitly converts Math.Pow
’s double
return value to a decimal
.
The for
statement’s body contains the calculation 1.0 + rate
, which appears as an argument to the Math.Pow
method. In fact, this calculation produces the same result each time through the loop, so repeating the calculation in every iteration of the loop is wasteful.
In loops, avoid calculations for which the result never changes—such calculations should typically be placed before the loop. Optimizing compilers will typically do this for you.
After each calculation, line 23
Console.WriteLine($"{year,4}{amount,20:C}");
displays the year and the amount on deposit at the end of that year. The interpolation expression
{year,4}
formats the year
. The integer 4
after the comma indicates that the value output should be displayed with a field width of 4—that is, WriteLine
displays the value with at least four character positions. If the value to be output is fewer than four character positions wide (one or two characters in this example), the value is right-aligned in the field by default— in this case the value is preceded by two or three spaces, depending on the year
value. If the value to be output were more than four character positions wide, the field width would be extended to the right to accommodate the entire value—this would push the amount
column to the right, upsetting the neat columns of our tabular output. Similarly, the interpolation expression
{amount,20:C}
formats the amount
as currency (C
) right-aligned in a field of at least 20 characters. To left align a value, simply use a negative field width.
float
or double
for Monetary AmountsSection 4.9 introduced the simple type decimal
for precise monetary representation and calculations. You might be tempted to use the floating-point types float
or double
for such calculations. However, for certain values types float
or double
suffer from what we call representational error. For example, floating-point numbers often arise as a result of calculations—when we divide 10 by 3, the result is 3.3333333…, with the sequence of 3s repeating infinitely. The computer allocates only a fixed amount of space to hold such a value, so clearly the stored floating-point value can be only an approximation.
Using floating-point numbers in a manner that assumes they’re represented exactly (e.g., using them in comparisons for equality) can lead to incorrect results. Floating-point numbers are represented only approximately.
Do not use variables of type Floating-point numbers have numerous applications, especially for measured values. For example, when we speak of a “normal” body temperature of 98.6 degrees Fahrenheit, we need not be precise to a large number of digits. When we read the temperature on a thermometer as 98.6, it may actually be 98.5999473210643. Calling this number simply 98.6 is fine for most applications involving body temperatures. Similarly, we used type Two but a person adding the individual numbers as displayed would expect the sum to be 32.90. You’ve been warned! For people who work with programming languages that do not support a type like Error-Prevention Tip 6.5
double
(or float
) to perform precise monetary calculations— use type decimal
instead. The imprecision of floating-point numbers can cause errors that will result in incorrect monetary values.Applications of Floating-Point Numbers
double
to perform class-average calculations in Chapter 5. Due to the imprecise nature of floating-point numbers, type double
is preferred over type float
, because double
variables can represent floating-point numbers more precisely. For this reason, we use type double
throughout the book, unless we’re manipulating monetary amounts, in which case we use type decimal
.A Warning About Displaying Rounded Values
double
dollar amounts stored in the machine could be 14.234 (which would normally be rounded to 14.23 for display purposes) and 18.673 (which would normally be rounded to 18.67 for display purposes). When these amounts are added, they produce the internal sum 32.907, which would normally be rounded to 32.91 for display purposes. Thus, your output could appear as
14.23
+ 18.67
-------
32.91
decimal
for precise monetary calculations, Exercise 6.18 explores the use of integers to perform such calculations.