Amortization table

I'm doing an assignment where I have to create an Amortization table. I personally have no clue how loans work but gave it my best shot when writing the code. I think that I'm close to finishing it but I can't get the output to display and I don't know why. I figure I would ask before making things more complicated for myself.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <cmath>
#include <cstdlib>

using namespace std;

double inputPrincipal();
double inputAIR();
int inputTOF();
int inputPPY();
double computeAmortizedPayment(double p, double ir, double ppy, int n);
void printHeaderInformation(double princ, double ir, double amort, int n);
double computeInterestPortion(double remaining_balance, double ir, int ppy);
void computeAndPrintRows(double p, double ir, double amort, int n, int ppy);

int main()
{
	double p = 0.0;     // declare a variable to store an input value
	double ar = 0.0;    // declare a variable to store an input value
	int t = 0;          // declare a variable to store an input value
	int py = 0;         // declare a variable to store an input value
	double a = 0.0;     // stores the amortized payment
	p = inputPrincipal();    // input the Principal
	ar = inputAIR();    // input the Annual Interest Rate
	t = inputTOF();    // input the Term of the Loan
	py = inputPPY();    // input the Payments per Year

	// compute the Amortized Payment
	a = computeAmortizedPayment(p, ar, t, py);
	// output the value...
	printHeaderInformation(p, ar, t, py);
	cout.precision(2);
	// exit the program with success (0 == success)
	return 0;
}
double inputPrincipal()
{
	double num = 0.0;   
	bool is_valid_input = false;    
	while (is_valid_input == false)  
	{
		cout << "Please enter an Principal that is > 0: ";   
		cin >> num;                               
		
		if (num > 0)
		{			
			is_valid_input = true;
		}
		else
		{			
			cout << "ERROR: The Principal must be greater than zero (0)." << endl;
		}
	}
	
	return num;
}
double inputAIR()
{
	double rate = 0.0;   
	bool is_valid_input = false;    
	while (is_valid_input == false)  
	{
		cout << "Please enter a Annual Interest Rate that is in the range of [1-100]: ";   
		cin >> rate;                               
		
		if (rate > 1 && rate <= 100)
		{			
			is_valid_input = true;
		}
		else
		{			
			cout << "ERROR: The AIR has to be [1-100]" << endl;
		}
	}	
	return rate;
}
int inputTOF()
{
	int loan = 0;   
	bool is_valid_input = false;    
	while (is_valid_input == false)  
	{
		cout << "Please enter a Term of the Loan that is in the range of [10-30]: ";   
		cin >> loan;                               
		
		if (loan > 10 && loan <= 30)
		{			
			is_valid_input = true;
		}
		else
		{
			cout << "ERROR: The TOF has to be [10-30]" << endl;
		}
	}
	return loan;
}
int inputPPY()
{
	int pay = 0;   
	bool is_valid_input = false;    
	while (is_valid_input == false)  
	{
		cout << "Please enter a Payments per Year that is in the range of [1-12]: ";   
		cin >> pay;                               		
		if (pay > 1 && pay <= 12)
		{			
			is_valid_input = true;
		}
		else
		{
			cout << "ERROR: The PPY has to be [1-12]" << endl;
		}
	}
	return pay;
}
double computeAmortizedPayment(double p, double ir, double ppy, int n)
{
	double a = 0.0;
	a = (p * ir * pow((ir + 1), n)) / (pow((ir + 1), n) - 1);
	return a;
}
void printHeaderInformation(double princ, double ir, double amort, int n)
{
	cout << "\nBeginning Principal: " << princ << endl;
	cout << "Annual Interest Rate: " << ir << endl;
	cout << "Total Payments: " << n << endl;
	cout << "Payment Amount: " << amort << endl;
	cout << setw(5) << "\nPayment#" << setw(20) << "Interest Due" << setw(20) << "Principal" << setw(25) << "Balance Remaining" << endl;
}
double computeInterestPortion(double remaining_balance, double ir, int ppy)
{
	return (remaining_balance * (ir / 100.0)) / ppy;
}
void computeAndPrintRows(double p, double ir, double amort, int n, int ppy)
{

}
1
2
3
4
void computeAndPrintRows(double p, double ir, double amort, int n, int ppy)
{
    //There is nothing here.
}


Your function does nothing and is never called. You need to pass it arguments and call it. I'm sorry for stating the obvious.
Last edited on
it is unusual to deal with money via doubles. Most use integers, where 1 is the lowest value possible, eg a penny. You get rounding and representation problems with floating point.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
double computeAndPrintRows(double p, double ir, double amort, int n, int ppy)
{
    //if you calculated the payment correctly the principal will reduce to zero
    //I would not calculate the payment in this function I would pass it that value.
    //just run this function in a for loop for the number of payments.
    //You don't need to pass the interest because it is paid before principal so there is never 
    //carrying value for interest. You do need to pass the annual interest rate/number of payments per year. 


    return p;  // this should be the principal after it has been reduced  
}


Last edited on
Thank you for replying! Don't feel sorry for stating the obvious, I was working on it for a while trying to figure it out and my head was wracked by the end. What's the point in asking others for help if they don't point out the things you don't see.

I figured if I did double it would account for pennies, allowing values like $12.43 to be calculated.

When I enter the inputs the "Payment Amount:" defaults to the Term of the Loan. At first I thought it was an equation issue but I'm not sure. I think the equation for calculating the principal is correct so I may just be linking somethings up incorrectly. I corrected the argument in lines 18-20 and 128 where I had "amort" instead of "a", since "amort" didn't mean anything.

The last function is blank because I'm not sure how I would go about placing things into the rows. Would I "setw" the output into each column? I assume that's the best way to do it.

Sorry for not explaining all that before!
The reason for using ints for money is that double can be 'inaccurate'. eg working in decimal, what is the exact value of 1 / 3? The same applies to real numbers in binary. ints are always exact, so there's no problem with rounding, representation etc.
You have to much going on in code you submitted to get an answer. You need to write tests for your functions. Test each function separately, If you can't think up a test for a function you should probably rewrite the function. I would suggest you design a test before you write any function.

Here is an example of a test I designed to ensure that principal was reduced to zero in 60 payments:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include<iostream>
#include<iomanip>

double computeAndPrintRows(const double principal, 
                           const double payment, 
                           const double interest, 
                           const int    payment_per_period, 
                           const int    cnt) {

    double this_periods_interest = principal * (interest/payment_per_period);
    double principal_paid        = principal < (payment - this_periods_interest) ? principal : (payment - this_periods_interest);
    double balance               = principal - principal_paid;

    std::cout << std::fixed
              << std::setprecision(2)
              << std::setw(5)
              << cnt 
              << std::setw(20)
              << this_periods_interest 
              << std::setw(20)
              << principal_paid
              << std::setw(25)
              << balance
              << '\n';

    return balance;
}

int main () {

/*
   Information needed for test
    20,000   Loan
    2.5%     Annual Interest
    60       Payments (5 * 12 = 60) 
    354.95   Monthly Payment
    
    Source: https://www.amortization-calc.com/auto-car-loan-calculator/ 
*/
    std::cout << std::setw(5) << "\nPayment#" << std::setw(20) << "Interest Due" << std::setw(20) << "Principal" << std::setw(25) << "Balance Remaining" << '\n';

    int cnt{1};
    double principal{20000};
    double interest{.025};
    double payment {354.95};
    int payment_per_period{12};


    for(; principal > 0; ++cnt) {
        principal = computeAndPrintRows(principal, payment, interest , payment_per_period, cnt); 
    }
    
    return 0;
}
Last edited on
Thank you very much for the example code. I see now how over complicated I made mine. I was not taught in my course to test the functions separately before introducing them with the rest of the code.
You should also take note of the use of more meaningful variable names. Using meaningful variable and function names help document the code and actually make it easier to follow the program logic. Also trying to find all occurrences of single letter variable names is almost impossible, save single variable names for very limited scopes such as for() loop "counter" variables.


$12.43
is safer as 1243 cents. Trust me on this :) You can find countless dissertations on the issues with floating point to read when you have time to do so.
It may not matter for homework, but one of the things to have pop into your head when someone talks about a program that handles money should immediately be "this probably needs to be done with integers".

There are times when you are just stuck and have to juggle the math/tools to fit, eg converting currency from one to another may require "floating point" of some flavor (which may become an exotic thing under the hood, but it will look like floating point)
Last edited on
Topic archived. No new replies allowed.