Reputation: 21
I created the program below for an assignment. You are supposed to be able enter in your original principal, minimum interest rate, maximum interest rate, and number of years to accumulate interest.
After testing it, everything works just fine unless I input my maximum interest as .06, .6, etc. For some reason, it will not display the maximum interest. If I input .06 as the minimum interest, it displays successfully, and if I use a maximum interest amount higher than .06, it will display the .06 amount. There is no other amount that presents me with a problem.
Would anyone be able to assist me in figuring out what I need to change to correct this?
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
//variables & named constants
int principal = 0;
double minimumInterest = 0.0;
double maximumInterest = 0.0;
int yearBase = 1;
int years = 0;
double balance = 0.0;
//inputs
cout << "Enter the beginning principal: $";
cin >> principal;
cout << "Enter the minimum interest rate: ";
cin >> minimumInterest;
cout << "Enter the maximum interest rate: ";
cin >> maximumInterest;
cout << "Enter the number of years the interest will accumlate: ";
cin >> years;
//calculations & loop
do
{
cout << "Year " << yearBase << ":" << endl;
for (double rate = minimumInterest; rate <= maximumInterest; rate += .01)
{
balance = principal * pow(1 + rate, yearBase);
//display rate with zero decimal places
cout << fixed << setprecision(0);
cout << " Rate " << rate * 100 << "%: $";
//display balance with two decimal places
cout << setprecision(2) << balance << endl;
}
//update years counter
yearBase +=1;
} while (yearBase <= years);
system("pause");
return 0;
}
Upvotes: 2
Views: 448
Reputation: 324
The answer about the floating point inaccuracies is correct and is the reason you don't use floating point numbers when talking money.
A quick hack that would allow you to work with little modification would be to change:
for (double rate = minimumInterest; rate <= maximumInterest; rate += .01)
to:
for (double rate = minimumInterest; rate <= (maximumInterest+0.001); rate += .01)
And it would work. Anyway your money calculations will be wrong at some point.
A correct implementation would use fixed point arithmetic.
Upvotes: 1
Reputation: 153955
Well, double
doesn't represent decimal values exactly: It is a binary floating point, i.e., its internal representation is _(-1)sign * significant * 2exponent where sign is 0 or 1, significant an unsigned integer, and exponent a signed integer. It is a relatively simple argument showing that you cannot represent, e.g., 0.01 or 0.6 exactly. That is, the computation of adding 0.01 sixty times is probably not 0.6. In fact, if you print these values with enough digits, you can see the effect:
#include <iostream>
#include <iomanip>
#include <limits>
int main()
{
double sum;
double small(0.01);
double big(0.6);
for (int i(0); i != 60; ++i) {
sum += small;
}
std::cout << std::setprecision(std::numeric_limits<double>::digits10 + 4)
<< "small=" << small << "\n"
<< "big=" << big << "\n"
<< "sum=" << sum << "\n";
}
Running this program will yield something like this:
small=0.01000000000000000021
big=0.5999999999999999778
sum=0.6000000000000003109
If you want to see the exact values the computation used, you'd need to set the precision to std::numeric_limits<double>::digits
. It won't look pretty, though.
Now for the interesting question of how to deal with problems like this? A general solution when computing with decimal number is to use decimal floating points but there are only in the process of being proposed to be added to the C++ standard library. You could maintain the interest rate exactly. For your specific setup the easiest approach is probably to not use the interest rate to control the execution of your loop but rather use a suitable counter.
Upvotes: 1